From faf83004e2eff94eca87c310aadf63dcd24226ce Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 30 Jan 2022 21:59:12 +0530 Subject: [PATCH 001/466] reverted to noraml logic in video details --- .flutter-plugins-dependencies | 2 +- .packages | 2 +- lib/main.dart | 14 ++++- .../video_details_screen.dart | 61 +++++++++++-------- .../video_details_view_model.dart | 17 +++--- .../video_details_widgets.dart | 43 +++++++------ 6 files changed, 78 insertions(+), 61 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index dcc97096..95c94acd 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-01-30 16:27:43.690884","version":"2.8.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-01-30 21:57:55.025429","version":"2.8.1"} \ No newline at end of file diff --git a/.packages b/.packages index 3dcda11b..e3dda57a 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-01-30 16:15:49.484679. +# Generated by pub on 2022-01-30 21:41:47.163681. args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ boolean_selector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/ diff --git a/lib/main.dart b/lib/main.dart index 77a47a90..53cf10a3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; @@ -31,9 +32,18 @@ class MyApp extends StatelessWidget { return MaterialApp( title: 'Acela - 3Speak App', theme: ThemeData.dark(), + onGenerateRoute: (settings) { + if (settings.name == VideoDetailsScreen.routeName) { + final args = settings.arguments as VideoDetailsScreenArguments; + return MaterialPageRoute(builder: (context) { + return VideoDetailsScreen( + vm: VideoDetailsViewModel(item: args.item)); + }); + } + assert(false, 'Need to implement ${settings.name}'); + return null; + }, routes: { - VideoDetailsScreen.routeName: (context) => - futureBuilder(const VideoDetailsScreen()), '/': (context) => futureBuilder(const HomeScreen()), }, // home: const HomeScreen(), diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 1fbf0d6e..42be759b 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -13,7 +13,9 @@ class VideoDetailsScreenArguments { } class VideoDetailsScreen extends StatefulWidget { - const VideoDetailsScreen({Key? key}) : super(key: key); + const VideoDetailsScreen({Key? key, required this.vm}) : super(key: key); + final VideoDetailsViewModel vm; + static const routeName = '/video_details'; @override @@ -22,51 +24,58 @@ class VideoDetailsScreen extends StatefulWidget { class _VideoDetailsScreenState extends State { final widgets = VideoDetailsScreenWidgets(); - VideoPlayerController? _controller; - VideoDetailsViewModel? vm; + late VideoPlayerController controller; @override void dispose() { super.dispose(); - _controller?.dispose(); + controller.dispose(); } - void initPlayer(String url) { - _controller ??= VideoPlayerController.network(url) + @override + void initState() { + String url = widget.vm.item.ipfs == null + ? "https://threespeakvideo.b-cdn.net/${widget.vm.item.permlink}/default.m3u8" + : "https://ipfs-3speak.b-cdn.net/ipfs/${widget.vm.item.ipfs}/default.m3u8"; + controller = VideoPlayerController.network(url) ..initialize().then((_) { setState(() { - _controller?.play(); + controller.play(); }); }); + super.initState(); + } + + Widget videoPlayer() { + return Center( + child: controller.value.isInitialized + ? VideoPlayer(controller) + : Container(), + ); } void initViewModel(BuildContext context) { - final args = ModalRoute.of(context)!.settings.arguments - as VideoDetailsScreenArguments; - vm ??= VideoDetailsViewModel( - stateUpdated: () { - setState(() {}); - }, - item: args.item); - vm?.loadVideoInfo(); - vm?.loadComments(args.item.owner, args.item.permlink); + widget.vm.loadVideoInfo(() { + setState(() {}); + }); + widget.vm.loadComments(widget.vm.item.owner, widget.vm.item.permlink,() { + setState(() {}); + }); } @override Widget build(BuildContext context) { initViewModel(context); - Widget videoView = widgets.getPlayer(context, _controller, initPlayer); - FloatingActionButton btn = widgets.getFab(_controller, () { + Widget videoView = videoPlayer(); + FloatingActionButton btn = widgets.getFab(controller, () { setState(() { - _controller?.value.isPlaying ?? false - ? _controller?.pause() - : _controller?.play(); + controller.value.isPlaying + ? controller.pause() + : controller.play(); }); }); - return widgets.tabBar( - context, - btn, - videoView, - vm); + return widgets.tabBar(context, btn, videoView, widget.vm, () { + setState(() {}); + }); } } diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index f833fbb9..2d36686f 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -14,7 +14,6 @@ class VideoDetailsViewModel { VideoDetailsDescription? description; // view - Function() stateUpdated; HomeFeed item; // loading comments @@ -22,9 +21,9 @@ class VideoDetailsViewModel { String commentsError = 'Something went wrong'; List comments = []; - VideoDetailsViewModel({required this.stateUpdated, required this.item}); + VideoDetailsViewModel({required this.item}); - void loadVideoInfo() { + void loadVideoInfo(Function stateUpdated) { if (descState != LoadState.notStarted) return; descState = LoadState.loading; stateUpdated(); @@ -44,7 +43,7 @@ class VideoDetailsViewModel { }); } - void loadComments(String author, String permlink) { + void loadComments(String author, String permlink, Function stateUpdated) { if (commentsState != LoadState.notStarted) return; commentsState = LoadState.loading; var client = http.Client(); @@ -59,7 +58,7 @@ class VideoDetailsViewModel { commentsState = LoadState.succeeded; comments = hiveComments.result; stateUpdated(); - scanComments(); + scanComments(stateUpdated); }).catchError((error) { commentsError = 'Something went wrong.\nError is $error'; commentsState = LoadState.failed; @@ -67,7 +66,7 @@ class VideoDetailsViewModel { }); } - void childrenComments(String author, String permlink, int index) { + void childrenComments(String author, String permlink, int index, Function stateUpdated) { var client = http.Client(); var request = http.Request('POST', Uri.parse(server.hiveDomain)); request.body = @@ -79,7 +78,7 @@ class VideoDetailsViewModel { HiveComments hiveComments = hiveCommentsFromJson(value); comments.insertAll(index + 1, hiveComments.result); stateUpdated(); - scanComments(); + scanComments(stateUpdated); }).catchError((error) { // commentsError = 'Something went wrong.\nError is $error'; // commentsState = LoadState.failed; @@ -87,11 +86,11 @@ class VideoDetailsViewModel { }); } - void scanComments() { + void scanComments(Function stateUpdated) { for(var i=0; i < comments.length; i++) { if (comments[i].children > 0) { if (comments.where((e) => e.parentPermlink == comments[i].permlink).isEmpty) { - childrenComments(comments[i].author, comments[i].permlink, i); + childrenComments(comments[i].author, comments[i].permlink, i, stateUpdated); break; } } diff --git a/lib/src/screens/video_details_screen/video_details_widgets.dart b/lib/src/screens/video_details_screen/video_details_widgets.dart index 0d2661ab..dc8b14be 100644 --- a/lib/src/screens/video_details_screen/video_details_widgets.dart +++ b/lib/src/screens/video_details_screen/video_details_widgets.dart @@ -21,10 +21,9 @@ class VideoDetailsScreenWidgets { BuildContext context, FloatingActionButton fab, Widget videoView, - VideoDetailsViewModel? vm, + VideoDetailsViewModel vm, + Function stateUpdated, ) { - final args = ModalRoute.of(context)!.settings.arguments - as VideoDetailsScreenArguments; return DefaultTabController( length: tabs.length, child: Builder( @@ -32,14 +31,14 @@ class VideoDetailsScreenWidgets { // final TabController tabController = DefaultTabController.of(context)!; return Scaffold( appBar: AppBar( - title: Text(args.item.title), + title: Text(vm.item.title), bottom: const TabBar(tabs: tabs), ), body: TabBarView( children: [ videoView, - getDescription(context, vm), - getComments(context, vm) + getDescription(context, vm, stateUpdated), + getComments(context, vm, stateUpdated) ], ), floatingActionButton: fab, @@ -58,23 +57,23 @@ class VideoDetailsScreenWidgets { ); } - Widget getDescription(BuildContext context, VideoDetailsViewModel? vm) { - return vm?.descState == LoadState.loading + Widget getDescription(BuildContext context, VideoDetailsViewModel vm, Function stateUpdated) { + return vm.descState == LoadState.loading ? const LoadingScreen() - : vm?.descState == LoadState.failed + : vm.descState == LoadState.failed ? RetryScreen( - error: vm?.descError ?? "Something went wrong", + error: vm.descError, onRetry: () { - vm?.descState = LoadState.notStarted; - vm?.loadVideoInfo(); + vm.descState = LoadState.notStarted; + vm.loadVideoInfo(stateUpdated); }) - : descriptionMarkDown(vm!.description!.description); + : descriptionMarkDown(vm.description!.description); } - Widget commentsListView(VideoDetailsViewModel? vm) { + Widget commentsListView(VideoDetailsViewModel vm) { return ListView.separated( itemBuilder: (context, index) { - var item = vm!.comments[index]; + var item = vm.comments[index]; var userThumb = server.userOwnerThumb(item.author); var author = item.author; var body = item.body; @@ -120,18 +119,18 @@ class VideoDetailsScreenWidgets { height: 10, color: Colors.blueGrey, ), - itemCount: vm!.comments.length); + itemCount: vm.comments.length); } - Widget getComments(BuildContext context, VideoDetailsViewModel? vm) { - return vm?.commentsState == LoadState.loading + Widget getComments(BuildContext context, VideoDetailsViewModel vm, Function stateUpdated) { + return vm.commentsState == LoadState.loading ? const LoadingScreen() - : vm?.commentsState == LoadState.failed + : vm.commentsState == LoadState.failed ? RetryScreen( - error: vm?.commentsError ?? "Something went wrong", + error: vm.commentsError, onRetry: () { - vm?.commentsState = LoadState.notStarted; - vm?.loadComments(vm.item.owner, vm.item.permlink); + vm.commentsState = LoadState.notStarted; + vm.loadComments(vm.item.owner, vm.item.permlink, stateUpdated); }) : commentsListView(vm); } From a82f586b796f11f90ba11869d70d2d7307eb7d1a Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 31 Jan 2022 11:45:47 +0530 Subject: [PATCH 002/466] video player with seek bar, aspect ratio --- .flutter-plugins-dependencies | 2 +- acela.iml | 6 ++ lib/src/screens/home_screen/home_screen.dart | 24 ++--- .../home_screen/home_screen_view_model.dart | 13 --- .../video_details_screen.dart | 11 +-- .../video_details_widgets.dart | 47 +++++----- lib/src/widgets/controls_overlay.dart | 90 +++++++++++++++++++ 7 files changed, 133 insertions(+), 60 deletions(-) create mode 100644 lib/src/widgets/controls_overlay.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 95c94acd..bafd38a1 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-01-30 21:57:55.025429","version":"2.8.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-01-31 11:24:36.852809","version":"2.8.1"} \ No newline at end of file diff --git a/acela.iml b/acela.iml index dec007d1..e252fd93 100644 --- a/acela.iml +++ b/acela.iml @@ -54,6 +54,12 @@ + + + + + + diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index d58f99d3..c71b57cc 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -32,24 +32,11 @@ class _HomeScreenState extends State { } Widget _screen() { - return FutureBuilder( - future: vm.getHomeFeed(), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.hasError) { - return RetryScreen( - error: snapshot.error as String, onRetry: vm.loadHomeFeed); - } else if (snapshot.hasData) { - return widgets.list( - snapshot.data as List, vm.loadHomeFeed, onTap); - } else { - return widgets.loadingData(); - } - } else { - return widgets.loadingData(); - } - }, - ); + return vm.state == LoadState.loading + ? widgets.loadingData() + : vm.state == LoadState.failed + ? RetryScreen(error: vm.error, onRetry: vm.loadHomeFeed) + : widgets.list(vm.list, vm.loadHomeFeed, onTap); } @override @@ -63,3 +50,4 @@ class _HomeScreenState extends State { ); } } +// https://3speak.tv/apiv2/feeds/trending \ No newline at end of file diff --git a/lib/src/screens/home_screen/home_screen_view_model.dart b/lib/src/screens/home_screen/home_screen_view_model.dart index 87bdedaa..9efe7567 100644 --- a/lib/src/screens/home_screen/home_screen_view_model.dart +++ b/lib/src/screens/home_screen/home_screen_view_model.dart @@ -34,17 +34,4 @@ class HomeScreenViewModel { stateUpdated(); } } - - Future> getHomeFeed() async { - final endPoint = "${server.domain}/api/feed/more"; - var response = await get(Uri.parse(endPoint)); - if (response.statusCode == 200) { - List list = homeFeedFromJson(response.body); - return list; - } else { - error = - 'Something went wrong.\nStatus code is ${response.statusCode} for $endPoint'; - throw error; - } - } } \ No newline at end of file diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 42be759b..87dfb882 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -66,15 +66,10 @@ class _VideoDetailsScreenState extends State { @override Widget build(BuildContext context) { initViewModel(context); - Widget videoView = videoPlayer(); - FloatingActionButton btn = widgets.getFab(controller, () { - setState(() { - controller.value.isPlaying - ? controller.pause() - : controller.play(); - }); + Widget videoView = widgets.getPlayer(context, controller, (p0) => { + }); - return widgets.tabBar(context, btn, videoView, widget.vm, () { + return widgets.tabBar(context, videoView, widget.vm, () { setState(() {}); }); } diff --git a/lib/src/screens/video_details_screen/video_details_widgets.dart b/lib/src/screens/video_details_screen/video_details_widgets.dart index dc8b14be..59151e7c 100644 --- a/lib/src/screens/video_details_screen/video_details_widgets.dart +++ b/lib/src/screens/video_details_screen/video_details_widgets.dart @@ -1,7 +1,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; +import 'package:acela/src/widgets/controls_overlay.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/retry.dart'; @@ -19,16 +19,14 @@ class VideoDetailsScreenWidgets { Widget tabBar( BuildContext context, - FloatingActionButton fab, Widget videoView, VideoDetailsViewModel vm, - Function stateUpdated, + Function stateUpdated, ) { return DefaultTabController( length: tabs.length, child: Builder( builder: (context) { - // final TabController tabController = DefaultTabController.of(context)!; return Scaffold( appBar: AppBar( title: Text(vm.item.title), @@ -41,7 +39,6 @@ class VideoDetailsScreenWidgets { getComments(context, vm, stateUpdated) ], ), - floatingActionButton: fab, ); }, ), @@ -57,7 +54,8 @@ class VideoDetailsScreenWidgets { ); } - Widget getDescription(BuildContext context, VideoDetailsViewModel vm, Function stateUpdated) { + Widget getDescription( + BuildContext context, VideoDetailsViewModel vm, Function stateUpdated) { return vm.descState == LoadState.loading ? const LoadingScreen() : vm.descState == LoadState.failed @@ -78,8 +76,7 @@ class VideoDetailsScreenWidgets { var author = item.author; var body = item.body; var upVotes = item.activeVotes.where((e) => e.percent > 0).length; - var downVotes = - item.activeVotes.where((e) => e.percent < 0).length; + var downVotes = item.activeVotes.where((e) => e.percent < 0).length; var payout = item.pendingPayoutValue.replaceAll(" HBD", ""); var timeInString = "📆 ${timeago.format(item.created)}"; var text = @@ -99,7 +96,10 @@ class VideoDetailsScreenWidgets { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - MarkdownBody(data: body, shrinkWrap: true,), + MarkdownBody( + data: body, + shrinkWrap: true, + ), Container(margin: const EdgeInsets.only(bottom: 10)), Text( text, @@ -122,7 +122,8 @@ class VideoDetailsScreenWidgets { itemCount: vm.comments.length); } - Widget getComments(BuildContext context, VideoDetailsViewModel vm, Function stateUpdated) { + Widget getComments( + BuildContext context, VideoDetailsViewModel vm, Function stateUpdated) { return vm.commentsState == LoadState.loading ? const LoadingScreen() : vm.commentsState == LoadState.failed @@ -130,22 +131,28 @@ class VideoDetailsScreenWidgets { error: vm.commentsError, onRetry: () { vm.commentsState = LoadState.notStarted; - vm.loadComments(vm.item.owner, vm.item.permlink, stateUpdated); + vm.loadComments( + vm.item.owner, vm.item.permlink, stateUpdated); }) : commentsListView(vm); } - Widget getPlayer(BuildContext context, VideoPlayerController? _controller, + Widget getPlayer(BuildContext context, VideoPlayerController controller, Function(String) initPlayer) { - final args = ModalRoute.of(context)!.settings.arguments - as VideoDetailsScreenArguments; - String url = args.item.ipfs == null - ? "https://threespeakvideo.b-cdn.net/${args.item.permlink}/default.m3u8" - : "https://ipfs-3speak.b-cdn.net/ipfs/${args.item.ipfs}/default.m3u8"; - initPlayer(url); return Center( - child: _controller?.value.isInitialized ?? false - ? VideoPlayer(_controller!) + child: controller.value.isInitialized ?? false + ? AspectRatio( + aspectRatio: controller.value.aspectRatio, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + VideoPlayer(controller), + ClosedCaption(text: controller.value.caption.text), + ControlsOverlay(controller: controller), + VideoProgressIndicator(controller, allowScrubbing: true), + ], + ), + ) : Container(), ); } diff --git a/lib/src/widgets/controls_overlay.dart b/lib/src/widgets/controls_overlay.dart new file mode 100644 index 00000000..08a0d483 --- /dev/null +++ b/lib/src/widgets/controls_overlay.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:video_player/video_player.dart'; + +class ControlsOverlay extends StatelessWidget { + const ControlsOverlay({Key? key, required this.controller}) + : super(key: key); + + static const _exampleCaptionOffsets = [ + Duration(seconds: -10), + Duration(seconds: -3), + Duration(seconds: -1, milliseconds: -500), + Duration(milliseconds: -250), + Duration(milliseconds: 0), + Duration(milliseconds: 250), + Duration(seconds: 1, milliseconds: 500), + Duration(seconds: 3), + Duration(seconds: 10), + ]; + static const _examplePlaybackRates = [ + 0.25, + 0.5, + 1.0, + 1.5, + 2.0, + 3.0, + 5.0, + 10.0, + ]; + + final VideoPlayerController controller; + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 50), + reverseDuration: const Duration(milliseconds: 200), + child: controller.value.isPlaying + ? const SizedBox.shrink() + : Container( + color: Colors.black26, + child: const Center( + child: Icon( + Icons.play_arrow, + color: Colors.white, + size: 100.0, + semanticLabel: 'Play', + ), + ), + ), + ), + GestureDetector( + onTap: () { + controller.value.isPlaying ? controller.pause() : controller.play(); + }, + ), + Align( + alignment: Alignment.topRight, + child: PopupMenuButton( + initialValue: controller.value.playbackSpeed, + tooltip: 'Playback speed', + onSelected: (speed) { + controller.setPlaybackSpeed(speed); + }, + itemBuilder: (context) { + return [ + for (final speed in _examplePlaybackRates) + PopupMenuItem( + value: speed, + child: Text('${speed}x'), + ) + ]; + }, + child: Padding( + padding: const EdgeInsets.symmetric( + // Using less vertical padding as the text is also longer + // horizontally, so it feels like it would need more spacing + // horizontally (matching the aspect ratio of the video). + vertical: 12, + horizontal: 16, + ), + child: Text('${controller.value.playbackSpeed}x'), + ), + ), + ), + ], + ); + } +} From f96135318b05c2cd12edef72b182c427d9c61b92 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 31 Jan 2022 15:19:07 +0530 Subject: [PATCH 003/466] integrated video details - full screen --- .flutter-plugins-dependencies | 2 +- .../video_details_screen.dart | 14 ++--------- .../video_details_widgets.dart | 23 ++++++++++++++----- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index bafd38a1..c1df83de 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-01-31 11:24:36.852809","version":"2.8.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-01-31 15:15:15.512054","version":"2.8.1"} \ No newline at end of file diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 87dfb882..0777e065 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -46,19 +46,11 @@ class _VideoDetailsScreenState extends State { super.initState(); } - Widget videoPlayer() { - return Center( - child: controller.value.isInitialized - ? VideoPlayer(controller) - : Container(), - ); - } - void initViewModel(BuildContext context) { widget.vm.loadVideoInfo(() { setState(() {}); }); - widget.vm.loadComments(widget.vm.item.owner, widget.vm.item.permlink,() { + widget.vm.loadComments(widget.vm.item.owner, widget.vm.item.permlink, () { setState(() {}); }); } @@ -66,9 +58,7 @@ class _VideoDetailsScreenState extends State { @override Widget build(BuildContext context) { initViewModel(context); - Widget videoView = widgets.getPlayer(context, controller, (p0) => { - - }); + Widget videoView = widgets.getPlayer(context, controller); return widgets.tabBar(context, videoView, widget.vm, () { setState(() {}); }); diff --git a/lib/src/screens/video_details_screen/video_details_widgets.dart b/lib/src/screens/video_details_screen/video_details_widgets.dart index 59151e7c..c28813d0 100644 --- a/lib/src/screens/video_details_screen/video_details_widgets.dart +++ b/lib/src/screens/video_details_screen/video_details_widgets.dart @@ -11,6 +11,7 @@ import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:video_player/video_player.dart'; class VideoDetailsScreenWidgets { + var showAppBar = true; static const List tabs = [ Tab(text: 'Video'), Tab(text: 'Description'), @@ -28,10 +29,12 @@ class VideoDetailsScreenWidgets { child: Builder( builder: (context) { return Scaffold( - appBar: AppBar( - title: Text(vm.item.title), - bottom: const TabBar(tabs: tabs), - ), + appBar: showAppBar + ? AppBar( + title: Text(vm.item.title), + bottom: const TabBar(tabs: tabs), + ) + : null, body: TabBarView( children: [ videoView, @@ -39,6 +42,15 @@ class VideoDetailsScreenWidgets { getComments(context, vm, stateUpdated) ], ), + floatingActionButton: FloatingActionButton( + child: showAppBar + ? const Icon(Icons.fullscreen) + : const Icon(Icons.fullscreen_exit), + onPressed: () { + showAppBar = !showAppBar; + stateUpdated(); + }, + ), ); }, ), @@ -137,8 +149,7 @@ class VideoDetailsScreenWidgets { : commentsListView(vm); } - Widget getPlayer(BuildContext context, VideoPlayerController controller, - Function(String) initPlayer) { + Widget getPlayer(BuildContext context, VideoPlayerController controller) { return Center( child: controller.value.isInitialized ?? false ? AspectRatio( From c0880d77af532b1e81235be789c25b2468891b4e Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 2 Feb 2022 00:13:58 +0530 Subject: [PATCH 004/466] integrated new home feed --- .flutter-plugins-dependencies | 2 +- .../home_feed_image.dart | 24 ++++++++ .../home_feed_models.dart | 56 ++++++++----------- .../home_screen/home_screen_view_model.dart | 2 +- .../home_screen/home_screen_widgets.dart | 6 +- .../video_details_screen.dart | 10 ++-- .../video_details_view_model.dart | 2 +- .../video_details_widgets.dart | 4 +- 8 files changed, 60 insertions(+), 46 deletions(-) create mode 100644 lib/src/models/home_screen_feed_models/home_feed_image.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index c1df83de..279e0d7c 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-01-31 15:15:15.512054","version":"2.8.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-02 00:11:02.633393","version":"2.8.1"} \ No newline at end of file diff --git a/lib/src/models/home_screen_feed_models/home_feed_image.dart b/lib/src/models/home_screen_feed_models/home_feed_image.dart new file mode 100644 index 00000000..fb049e67 --- /dev/null +++ b/lib/src/models/home_screen_feed_models/home_feed_image.dart @@ -0,0 +1,24 @@ +import 'dart:convert'; + +HomeFeedImage homeFeedImageFromJson(String str) => HomeFeedImage.fromJson(json.decode(str)); + +String homeFeedImageToJson(HomeFeedImage data) => json.encode(data.toJson()); + +class HomeFeedImage { + HomeFeedImage({ + required this.thumbnail, + }); + String thumbnail; + + factory HomeFeedImage.fromJson(Map json) { + final thumbnail = json['thumbnail'] as String?; + if (thumbnail == null) { + throw UnsupportedError('Invalid data: $json -> "thumbnail" is missing'); + } + return HomeFeedImage(thumbnail: thumbnail); + } + + Map toJson() => { + "thumbnail": thumbnail, + }; +} \ No newline at end of file diff --git a/lib/src/models/home_screen_feed_models/home_feed_models.dart b/lib/src/models/home_screen_feed_models/home_feed_models.dart index 21e02279..3d3b219b 100644 --- a/lib/src/models/home_screen_feed_models/home_feed_models.dart +++ b/lib/src/models/home_screen_feed_models/home_feed_models.dart @@ -1,5 +1,7 @@ import 'dart:convert'; +import 'package:acela/src/models/home_screen_feed_models/home_feed_image.dart'; + List homeFeedFromJson(String str) => List.from(json.decode(str).map((x) => HomeFeed.fromJson(x))); String homeFeedToJson(List data) => json.encode(List.from(data.map((x) => x.toJson()))); @@ -8,28 +10,24 @@ class HomeFeed { HomeFeed({ required this.created, required this.views, - required this.owner, + required this.author, required this.permlink, required this.title, required this.duration, - required this.isNsfwContent, - required this.tags_v2, - required this.thumbUrl, - required this.baseThumbUrl, + required this.playUrl, + required this.images, this.ipfs, }); DateTime created; int views; - String owner; + String author; String permlink; String title; double duration; - bool isNsfwContent; - List tags_v2; String? ipfs; - String thumbUrl; - String baseThumbUrl; + String playUrl; + HomeFeedImage images; factory HomeFeed.fromJson(Map json) { final created = json['created'] as String?; @@ -40,9 +38,9 @@ class HomeFeed { if (views == null) { throw UnsupportedError('Invalid data: $json -> "views" is missing'); } - final owner = json['owner'] as String?; - if (owner == null) { - throw UnsupportedError('Invalid data: $json -> "owner" is missing'); + final author = json['author'] as String?; + if (author == null) { + throw UnsupportedError('Invalid data: $json -> "author" is missing'); } final permlink = json['permlink'] as String?; if (permlink == null) { @@ -56,45 +54,37 @@ class HomeFeed { if (duration == null) { throw UnsupportedError('Invalid data: $json -> "duration" is missing'); } - final bool? isNsfwContent = json['isNsfwContent'] as bool?; - if (isNsfwContent == null) { - throw UnsupportedError('Invalid data: $json -> "isNsfwContent" is missing'); - } - final thumbUrl = json['thumbUrl'] as String?; - if (thumbUrl == null) { - throw UnsupportedError('Invalid data: $json -> "thumbUrl" is missing'); + final playUrl = json['playUrl'] as String?; + if (playUrl == null) { + throw UnsupportedError('Invalid data: $json -> "playUrl" is missing'); } - final baseThumbUrl = json['baseThumbUrl'] as String?; - if (baseThumbUrl == null) { - throw UnsupportedError('Invalid data: $json -> "baseThumbUrl" is missing'); + final images = json['images'] as Map?; + if (images == null) { + throw UnsupportedError('Invalid data: $json -> "images" is missing'); } final ipfs = json['ipfs'] as String?; return HomeFeed( created: DateTime.parse(created), views: views, - owner: owner, + author: author, permlink: permlink, title: title, duration: duration, - isNsfwContent: isNsfwContent, - tags_v2: json["tags_v2"] == null ? [] : List.from(json["tags_v2"].map((x) => x)), ipfs: ipfs, - thumbUrl: thumbUrl, - baseThumbUrl: baseThumbUrl, + playUrl: playUrl, + images: HomeFeedImage.fromJson(images), ); } Map toJson() => { "created": created.toIso8601String(), "views": views, - "owner": owner, + "author": author, "permlink": permlink, "title": title, "duration": duration, - "isNsfwContent": isNsfwContent, - "tags_v2": List.from(tags_v2.map((x) => x)), - "thumbUrl": thumbUrl, - "baseThumbUrl": baseThumbUrl, + "playUrl": playUrl, + "images": homeFeedImageToJson(images), "ipfs": ipfs, }; } \ No newline at end of file diff --git a/lib/src/screens/home_screen/home_screen_view_model.dart b/lib/src/screens/home_screen/home_screen_view_model.dart index 9efe7567..8fa30866 100644 --- a/lib/src/screens/home_screen/home_screen_view_model.dart +++ b/lib/src/screens/home_screen/home_screen_view_model.dart @@ -20,7 +20,7 @@ class HomeScreenViewModel { Future loadHomeFeed() async { state = LoadState.loading; stateUpdated(); - final endPoint = "${server.domain}/api/feed/more"; + final endPoint = "${server.domain}/apiv2/feeds/home"; var response = await get(Uri.parse(endPoint)); if (response.statusCode == 200) { List list = homeFeedFromJson(response.body); diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index 1da9e148..0c17fd7b 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -13,12 +13,12 @@ class HomeScreenWidgets { Widget _tileTitle(HomeFeed item, BuildContext context) { String timeInString = "📆 ${timeago.format(item.created)}"; - String owner = "👤 ${item.owner}"; + String owner = "👤 ${item.author}"; String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; return ListTileVideo( placeholder: 'assets/branding/three_speak_logo.png', - url: item.thumbUrl, - userThumbUrl: server.userOwnerThumb(item.owner), + url: item.images.thumbnail, + userThumbUrl: server.userOwnerThumb(item.author), title: item.title, subtitle: "$timeInString $owner $duration ▶ ${item.views}", ); diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 0777e065..690a94f6 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -34,10 +34,10 @@ class _VideoDetailsScreenState extends State { @override void initState() { - String url = widget.vm.item.ipfs == null - ? "https://threespeakvideo.b-cdn.net/${widget.vm.item.permlink}/default.m3u8" - : "https://ipfs-3speak.b-cdn.net/ipfs/${widget.vm.item.ipfs}/default.m3u8"; - controller = VideoPlayerController.network(url) + // String url = widget.vm.item.ipfs == null + // ? "https://threespeakvideo.b-cdn.net/${widget.vm.item.permlink}/default.m3u8" + // : "https://ipfs-3speak.b-cdn.net/ipfs/${widget.vm.item.ipfs}/default.m3u8"; + controller = VideoPlayerController.network(widget.vm.item.playUrl) ..initialize().then((_) { setState(() { controller.play(); @@ -50,7 +50,7 @@ class _VideoDetailsScreenState extends State { widget.vm.loadVideoInfo(() { setState(() {}); }); - widget.vm.loadComments(widget.vm.item.owner, widget.vm.item.permlink, () { + widget.vm.loadComments(widget.vm.item.author, widget.vm.item.permlink, () { setState(() {}); }); } diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index 2d36686f..67be5ece 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -27,7 +27,7 @@ class VideoDetailsViewModel { if (descState != LoadState.notStarted) return; descState = LoadState.loading; stateUpdated(); - final endPoint = "${server.domain}/apiv2/@${item.owner}/${item.permlink}"; + final endPoint = "${server.domain}/apiv2/@${item.author}/${item.permlink}"; get(Uri.parse(endPoint)) .then((response) { VideoDetailsDescription desc = diff --git a/lib/src/screens/video_details_screen/video_details_widgets.dart b/lib/src/screens/video_details_screen/video_details_widgets.dart index c28813d0..c4e3b833 100644 --- a/lib/src/screens/video_details_screen/video_details_widgets.dart +++ b/lib/src/screens/video_details_screen/video_details_widgets.dart @@ -144,14 +144,14 @@ class VideoDetailsScreenWidgets { onRetry: () { vm.commentsState = LoadState.notStarted; vm.loadComments( - vm.item.owner, vm.item.permlink, stateUpdated); + vm.item.author, vm.item.permlink, stateUpdated); }) : commentsListView(vm); } Widget getPlayer(BuildContext context, VideoPlayerController controller) { return Center( - child: controller.value.isInitialized ?? false + child: controller.value.isInitialized ? AspectRatio( aspectRatio: controller.value.aspectRatio, child: Stack( From d641a8fcbbc90d8e019d31471b6b20294507d471 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 2 Feb 2022 00:51:50 +0530 Subject: [PATCH 005/466] new content, trending content - added. fixed issue for large sized screen --- .flutter-plugins-dependencies | 2 +- lib/main.dart | 30 ++++++++++++++++--- .../screens/drawer_screen/drawer_screen.dart | 20 +++++++------ lib/src/screens/home_screen/home_screen.dart | 27 +++++++++++------ .../home_screen/home_screen_view_model.dart | 8 ++--- lib/src/widgets/list_tile_video.dart | 5 ++-- 6 files changed, 63 insertions(+), 29 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 279e0d7c..73014f06 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-02 00:11:02.633393","version":"2.8.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-02 00:49:30.034970","version":"2.8.1"} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 53cf10a3..2a3a8aa7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,6 +4,8 @@ import 'package:acela/src/screens/video_details_screen/video_details_view_model. import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; +import 'src/bloc/server.dart'; + Future main() async { WidgetsFlutterBinding.ensureInitialized(); runApp(MyApp()); @@ -39,14 +41,34 @@ class MyApp extends StatelessWidget { return VideoDetailsScreen( vm: VideoDetailsViewModel(item: args.item)); }); + } else if (settings.name == "/") { + return MaterialPageRoute(builder: (context) { + return HomeScreen( + path: "${server.domain}/apiv2/feeds/home", + showDrawer: true, + title: 'Home', + ); + }); + } else if (settings.name == "/trending") { + return MaterialPageRoute(builder: (context) { + return HomeScreen( + path: "${server.domain}/apiv2/feeds/trending", + showDrawer: false, + title: 'Trending Content', + ); + }); + } else if (settings.name == "/new") { + return MaterialPageRoute(builder: (context) { + return HomeScreen( + path: "${server.domain}/apiv2/feeds/new", + showDrawer: false, + title: 'New Content', + ); + }); } assert(false, 'Need to implement ${settings.name}'); return null; }, - routes: { - '/': (context) => futureBuilder(const HomeScreen()), - }, - // home: const HomeScreen(), ); } } diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 163f9ab1..df539ff8 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -3,12 +3,12 @@ import 'package:flutter/material.dart'; class DrawerScreen extends StatelessWidget { const DrawerScreen({Key? key}) : super(key: key); - Widget _homeMenu() { + Widget _homeMenu(BuildContext context) { return ListTile( leading: const Icon(Icons.home), title: const Text("Home"), onTap: () { - + Navigator.pop(context); }, ); } @@ -23,22 +23,24 @@ class DrawerScreen extends StatelessWidget { ); } - Widget _trendingContent() { + Widget _trendingContent(BuildContext context) { return ListTile( leading: const Icon(Icons.local_fire_department), title: const Text("Trending Content"), onTap: () { - + Navigator.pop(context); + Navigator.of(context).pushNamed("/trending"); }, ); } - Widget _newContent() { + Widget _newContent(BuildContext context) { return ListTile( leading: const Icon(Icons.play_arrow), title: const Text("New Content"), onTap: () { - + Navigator.pop(context); + Navigator.of(context).pushNamed("/new"); }, ); } @@ -91,13 +93,13 @@ class DrawerScreen extends StatelessWidget { return ListView( children: [ _drawerHeader(context), - _homeMenu(), + _homeMenu(context), const Divider(height: 1, color: Colors.blueGrey,), _firstUploads(), const Divider(height: 1, color: Colors.blueGrey,), - _trendingContent(), + _trendingContent(context), const Divider(height: 1, color: Colors.blueGrey,), - _newContent(), + _newContent(context), const Divider(height: 1, color: Colors.blueGrey,), _communities(), const Divider(height: 1, color: Colors.blueGrey,), diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index c71b57cc..f6ef3925 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -7,7 +7,15 @@ import 'package:flutter/material.dart'; import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; class HomeScreen extends StatefulWidget { - const HomeScreen({Key? key}) : super(key: key); + const HomeScreen( + {Key? key, + required this.path, + required this.showDrawer, + required this.title}) + : super(key: key); + final String path; + final bool showDrawer; + final String title; @override _HomeScreenState createState() => _HomeScreenState(); @@ -20,9 +28,11 @@ class _HomeScreenState extends State { @override void initState() { super.initState(); - vm = HomeScreenViewModel(stateUpdated: () { - setState(() {}); - }); + vm = HomeScreenViewModel( + path: widget.path, + stateUpdated: () { + setState(() {}); + }); vm.loadHomeFeed(); } @@ -35,19 +45,18 @@ class _HomeScreenState extends State { return vm.state == LoadState.loading ? widgets.loadingData() : vm.state == LoadState.failed - ? RetryScreen(error: vm.error, onRetry: vm.loadHomeFeed) - : widgets.list(vm.list, vm.loadHomeFeed, onTap); + ? RetryScreen(error: vm.error, onRetry: vm.loadHomeFeed) + : widgets.list(vm.list, vm.loadHomeFeed, onTap); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Home'), + title: Text(widget.title), ), body: _screen(), - drawer: const DrawerScreen(), + drawer: widget.showDrawer ? const DrawerScreen() : null, ); } } -// https://3speak.tv/apiv2/feeds/trending \ No newline at end of file diff --git a/lib/src/screens/home_screen/home_screen_view_model.dart b/lib/src/screens/home_screen/home_screen_view_model.dart index 8fa30866..79b9486f 100644 --- a/lib/src/screens/home_screen/home_screen_view_model.dart +++ b/lib/src/screens/home_screen/home_screen_view_model.dart @@ -15,13 +15,13 @@ class HomeScreenViewModel { String error = 'Something went wrong'; Function() stateUpdated; - HomeScreenViewModel({required this.stateUpdated}); + HomeScreenViewModel({required this.path, required this.stateUpdated}); + final String path; Future loadHomeFeed() async { state = LoadState.loading; stateUpdated(); - final endPoint = "${server.domain}/apiv2/feeds/home"; - var response = await get(Uri.parse(endPoint)); + var response = await get(Uri.parse(path)); if (response.statusCode == 200) { List list = homeFeedFromJson(response.body); state = LoadState.succeeded; @@ -29,7 +29,7 @@ class HomeScreenViewModel { stateUpdated(); } else { error = - 'Something went wrong.\nStatus code is ${response.statusCode} for $endPoint'; + 'Something went wrong.\nStatus code is ${response.statusCode} for $path'; state = LoadState.failed; stateUpdated(); } diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index 20754629..86766672 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -35,11 +35,12 @@ class ListTileVideo extends StatelessWidget { } Widget _listType(BuildContext context) { - double width = MediaQuery.of(context).size.width - 60 - 340; + double deviceWidth = MediaQuery.of(context).size.width; + double width = deviceWidth - 60 - 340; return Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Image.network(url), + Image.network(url, width: deviceWidth - width - 60, ), Container(width: 10), SizedBox( width: width, From 0d0f609d0664ad36b4cbeb222cb3f950f3772b02 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 3 Feb 2022 00:15:06 +0530 Subject: [PATCH 006/466] added icons, favicons for web. resized images for lower internet consumption. dark and light mode support for app --- .DS_Store | Bin 6148 -> 6148 bytes .flutter-plugins-dependencies | 2 +- .packages | 2 +- ios/Podfile.lock | 49 +++++++++++++ lib/main.dart | 45 +++++++++--- lib/src/bloc/server.dart | 5 ++ .../screens/drawer_screen/drawer_screen.dart | 66 +++++++++++++----- lib/src/screens/home_screen/home_screen.dart | 13 +++- lib/src/widgets/list_tile_video.dart | 16 ++--- web/favicon.png | Bin 917 -> 3513 bytes web/icons/Icon-192.png | Bin 5292 -> 23416 bytes web/icons/Icon-512.png | Bin 8252 -> 103955 bytes web/icons/Icon-maskable-192.png | Bin 5594 -> 23414 bytes web/icons/Icon-maskable-512.png | Bin 20998 -> 103953 bytes 14 files changed, 155 insertions(+), 43 deletions(-) diff --git a/.DS_Store b/.DS_Store index fbe691ba556146e9c3a21afa577fd7202134498f..22c7280d4c20d01af6e3b82503823e85c968543a 100644 GIT binary patch delta 158 zcmZoMXfc=|#>B)qu~2NHo+2a5#DLw4m>3yZCi5^p6J};8XGmp8N-8fdNXp4iVqjp{ zIa!IZP(!l1+StfUN5RnCvQ|f-+R(_<{9 delta 69 zcmZoMXfc=|#>B`mu~2NHo+2aD#DLwC4MbQb^D{l(e4W{VW%CE-r;MA~Iruq%iZ(xF Y{?0s^U&NAw0SFiw7??H(h-_g70K`KQod5s; diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 73014f06..df1f55d1 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-02 00:49:30.034970","version":"2.8.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-03 00:06:03.139110","version":"2.8.1"} \ No newline at end of file diff --git a/.packages b/.packages index e3dda57a..dfd0a3b0 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-01-30 21:41:47.163681. +# Generated by pub on 2022-02-02 23:56:23.211792. args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ boolean_selector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0c649f2f..37b3f2d3 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,20 +1,69 @@ PODS: + - Firebase/CoreOnly (8.11.0): + - FirebaseCore (= 8.11.0) + - firebase_core (1.12.0): + - Firebase/CoreOnly (= 8.11.0) + - Flutter + - FirebaseCore (8.11.0): + - FirebaseCoreDiagnostics (~> 8.0) + - GoogleUtilities/Environment (~> 7.7) + - GoogleUtilities/Logger (~> 7.7) + - FirebaseCoreDiagnostics (8.11.0): + - GoogleDataTransport (~> 9.1) + - GoogleUtilities/Environment (~> 7.7) + - GoogleUtilities/Logger (~> 7.7) + - nanopb (~> 2.30908.0) - Flutter (1.0.0) + - GoogleDataTransport (9.1.2): + - GoogleUtilities/Environment (~> 7.2) + - nanopb (~> 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Environment (7.7.0): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.7.0): + - GoogleUtilities/Environment + - nanopb (2.30908.0): + - nanopb/decode (= 2.30908.0) + - nanopb/encode (= 2.30908.0) + - nanopb/decode (2.30908.0) + - nanopb/encode (2.30908.0) + - PromisesObjC (2.0.0) - video_player (0.0.1): - Flutter DEPENDENCIES: + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - Flutter (from `Flutter`) - video_player (from `.symlinks/plugins/video_player/ios`) +SPEC REPOS: + trunk: + - Firebase + - FirebaseCore + - FirebaseCoreDiagnostics + - GoogleDataTransport + - GoogleUtilities + - nanopb + - PromisesObjC + EXTERNAL SOURCES: + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" Flutter: :path: Flutter video_player: :path: ".symlinks/plugins/video_player/ios" SPEC CHECKSUMS: + Firebase: 44dd9724c84df18b486639e874f31436eaa9a20c + firebase_core: 443bccfd6aa6b42f07be365b500773dc69db2d87 + FirebaseCore: 2f4f85b453cc8fea4bb2b37e370007d2bcafe3f0 + FirebaseCoreDiagnostics: 64d9709d804a6c25bd77841371c1fcfd909d5601 Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 + GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 + nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 + PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 video_player: ecd305f42e9044793efd34846e1ce64c31ea6fcb PODFILE CHECKSUM: 56099e53bf102df458f588dbe78632cd13d5357b diff --git a/lib/main.dart b/lib/main.dart index 2a3a8aa7..3cc5ef24 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,8 +11,16 @@ Future main() async { runApp(MyApp()); } -class MyApp extends StatelessWidget { +class MyApp extends StatefulWidget { + const MyApp({Key? key}) : super(key: key); + + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { final Future _fbApp = Firebase.initializeApp(); + bool isDarkMode = true; Widget futureBuilder(Widget withWidget) { return FutureBuilder( @@ -33,7 +41,8 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( title: 'Acela - 3Speak App', - theme: ThemeData.dark(), + theme: isDarkMode ? ThemeData.dark() : ThemeData.light(), + debugShowCheckedModeBanner: false, onGenerateRoute: (settings) { if (settings.name == VideoDetailsScreen.routeName) { final args = settings.arguments as VideoDetailsScreenArguments; @@ -47,23 +56,39 @@ class MyApp extends StatelessWidget { path: "${server.domain}/apiv2/feeds/home", showDrawer: true, title: 'Home', + isDarkMode: isDarkMode, + switchDarkMode: () { + setState(() { + isDarkMode = !isDarkMode; + }); + }, ); }); } else if (settings.name == "/trending") { return MaterialPageRoute(builder: (context) { return HomeScreen( - path: "${server.domain}/apiv2/feeds/trending", - showDrawer: false, - title: 'Trending Content', - ); + path: "${server.domain}/apiv2/feeds/trending", + showDrawer: false, + title: 'Trending Content', + isDarkMode: isDarkMode, + switchDarkMode: () { + setState(() { + isDarkMode = !isDarkMode; + }); + }); }); } else if (settings.name == "/new") { return MaterialPageRoute(builder: (context) { return HomeScreen( - path: "${server.domain}/apiv2/feeds/new", - showDrawer: false, - title: 'New Content', - ); + path: "${server.domain}/apiv2/feeds/new", + showDrawer: false, + title: 'New Content', + isDarkMode: isDarkMode, + switchDarkMode: () { + setState(() { + isDarkMode = !isDarkMode; + }); + }); }); } assert(false, 'Need to implement ${settings.name}'); diff --git a/lib/src/bloc/server.dart b/lib/src/bloc/server.dart index 3658dbe0..a238440c 100644 --- a/lib/src/bloc/server.dart +++ b/lib/src/bloc/server.dart @@ -1,3 +1,4 @@ +import 'dart:developer'; class Server { final String domain = "https://3speak.tv"; @@ -5,6 +6,10 @@ class Server { return "https://images.hive.blog/u/$value/avatar"; } + String resizedImage(String value) { + return "https://images.hive.blog/320x160/$value"; + } + final String hiveDomain = "https://api.hive.blog"; } diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index df539ff8..950a1d12 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -1,7 +1,12 @@ import 'package:flutter/material.dart'; class DrawerScreen extends StatelessWidget { - const DrawerScreen({Key? key}) : super(key: key); + const DrawerScreen( + {Key? key, required this.isDarkMode, required this.switchDarkMode}) + : super(key: key); + + final bool isDarkMode; + final Function switchDarkMode; Widget _homeMenu(BuildContext context) { return ListTile( @@ -17,9 +22,7 @@ class DrawerScreen extends StatelessWidget { return ListTile( leading: const Icon(Icons.emoji_emotions_outlined), title: const Text("First Uploads"), - onTap: () { - - }, + onTap: () {}, ); } @@ -49,9 +52,7 @@ class DrawerScreen extends StatelessWidget { return ListTile( leading: const Icon(Icons.people_sharp), title: const Text("Communities"), - onTap: () { - - }, + onTap: () {}, ); } @@ -59,8 +60,18 @@ class DrawerScreen extends StatelessWidget { return ListTile( leading: const Icon(Icons.leaderboard), title: const Text("Leaderboard"), - onTap: () { + onTap: () {}, + ); + } + Widget _changeTheme() { + return ListTile( + leading: isDarkMode + ? const Icon(Icons.wb_sunny) + : const Icon(Icons.mode_night), + title: const Text("Change Theme"), + onTap: () { + switchDarkMode(); }, ); } @@ -94,25 +105,46 @@ class DrawerScreen extends StatelessWidget { children: [ _drawerHeader(context), _homeMenu(context), - const Divider(height: 1, color: Colors.blueGrey,), + const Divider( + height: 1, + color: Colors.blueGrey, + ), _firstUploads(), - const Divider(height: 1, color: Colors.blueGrey,), + const Divider( + height: 1, + color: Colors.blueGrey, + ), _trendingContent(context), - const Divider(height: 1, color: Colors.blueGrey,), + const Divider( + height: 1, + color: Colors.blueGrey, + ), _newContent(context), - const Divider(height: 1, color: Colors.blueGrey,), + const Divider( + height: 1, + color: Colors.blueGrey, + ), _communities(), - const Divider(height: 1, color: Colors.blueGrey,), + const Divider( + height: 1, + color: Colors.blueGrey, + ), _leaderBoard(), - const Divider(height: 1, color: Colors.blueGrey,), + const Divider( + height: 1, + color: Colors.blueGrey, + ), + _changeTheme(), + const Divider( + height: 1, + color: Colors.blueGrey, + ), ], ); } @override Widget build(BuildContext context) { - return Drawer( - child: _drawerMenu(context) - ); + return Drawer(child: _drawerMenu(context)); } } diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index f6ef3925..86318281 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -11,11 +11,15 @@ class HomeScreen extends StatefulWidget { {Key? key, required this.path, required this.showDrawer, - required this.title}) + required this.title, + required this.isDarkMode, + required this.switchDarkMode}) : super(key: key); final String path; final bool showDrawer; final String title; + final bool isDarkMode; + final Function switchDarkMode; @override _HomeScreenState createState() => _HomeScreenState(); @@ -56,7 +60,12 @@ class _HomeScreenState extends State { title: Text(widget.title), ), body: _screen(), - drawer: widget.showDrawer ? const DrawerScreen() : null, + drawer: widget.showDrawer + ? DrawerScreen( + isDarkMode: widget.isDarkMode, + switchDarkMode: widget.switchDarkMode, + ) + : null, ); } } diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index 86766672..d0363ae3 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -1,3 +1,4 @@ +import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/utils/form_factor.dart'; import 'package:flutter/material.dart'; import 'custom_circle_avatar.dart'; @@ -21,15 +22,6 @@ class ListTileVideo extends StatelessWidget { Widget _commonContainer(BuildContext context, Widget child) { return Container( - decoration: const BoxDecoration( - boxShadow: [ - BoxShadow( - // color: Colors.grey, - // blurRadius: 10, - blurStyle: BlurStyle.outer, - ) - ], - ), child: child, ); } @@ -66,7 +58,7 @@ class ListTileVideo extends StatelessWidget { children: [ FadeInImage.assetNetwork( placeholder: placeholder, - image: url, + image: server.resizedImage(url), fit: BoxFit.cover, ), Container( @@ -79,9 +71,9 @@ class ListTileVideo extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title, style: Theme.of(context).textTheme.bodyText2), + Text(title, style: const TextStyle(fontSize: 15),), Container(height: 5), - Text(subtitle, style: Theme.of(context).textTheme.bodyText1) + Text(subtitle, style: const TextStyle(fontSize: 13),) ], ), ) diff --git a/web/favicon.png b/web/favicon.png index 8aaa46ac1ae21512746f852a42ba87e4165dfdd1..1af1f0292bc538c3e55e682ade88d2a41d43fca5 100644 GIT binary patch literal 3513 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 UHmF&bi~s-t07*qoM6N<$f)2C*K>z>% diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png index b749bfef07473333cf1dd31e9eed89862a5d52aa..4b387d0133c7df35da357f1d548bf7f0254047ef 100644 GIT binary patch literal 23416 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%0ArSuMfYdR~xWDN6vl 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 diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png index 88cfd48dff1169879ba46840804b412fe02fefd6..7cc68921da13f99bcabd6818ecb36cc17ae38736 100644 GIT binary patch literal 103955 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 z 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%0DoKY9=<*9SRJ~eL6 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 Q3OHOBFI+aQFm{dk4*`)r#Q*>R literal 8252 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 diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png index eb9b4d76e525556d5d89141648c724331630325d..aa6e10ac0ca4e7d7564c32cd4d4670d9c2524cbb 100644 GIT binary patch literal 23414 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 X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z! diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png index d69c56691fbdb0b7efa65097c7cc1edac12a6d3e..3b2c03c5ddb3c8e545bfe1a910229a1ee7005ff6 100644 GIT binary patch literal 103953 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 z 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 MPgg&ebxsLQ025IeI{*Lx From b3e9f3ff14d42333bc113b258de6534edc99b9e0 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 3 Feb 2022 00:29:13 +0530 Subject: [PATCH 007/466] reduced font size for mobile devices --- lib/src/widgets/list_tile_video.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index d0363ae3..8a14b962 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -32,7 +32,10 @@ class ListTileVideo extends StatelessWidget { return Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Image.network(url, width: deviceWidth - width - 60, ), + Image.network( + url, + width: deviceWidth - width - 60, + ), Container(width: 10), SizedBox( width: width, @@ -71,9 +74,10 @@ class ListTileVideo extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title, style: const TextStyle(fontSize: 15),), + Text(title, style: Theme.of(context).textTheme.bodyText2), Container(height: 5), - Text(subtitle, style: const TextStyle(fontSize: 13),) + Text(subtitle, + style: Theme.of(context).textTheme.bodyText1), ], ), ) From 179f842f3ae2a451c3f609a2c586ac8d3ec10280 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 4 Feb 2022 23:26:21 +0530 Subject: [PATCH 008/466] new data models --- .flutter-plugins | 4 +- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 344 +++++++++++++++++- .idea/libraries/Flutter_Plugins.xml | 6 +- .packages | 48 ++- .../request/hive_comments_request.dart | 45 ++- .../request/hive_comments_request.g.dart | 25 ++ .../hive_comments/response/active_vote.dart | 19 + .../hive_comments/response/active_vote.g.dart | 16 + .../hive_comments/response/hive_comment.dart | 34 ++ .../response/hive_comment.g.dart | 34 ++ .../hive_comments/response/hive_comments.dart | 80 +--- .../response/hive_comments.g.dart | 18 + .../home_feed_image.dart | 17 +- .../home_feed_image.g.dart | 17 + .../home_feed_models.dart | 73 +--- .../home_feed_models.g.dart | 33 ++ .../leaderboard_models.dart | 0 .../video_details_description.dart | 21 +- .../video_details_description.g.dart | 19 + .../home_screen/home_screen_widgets.dart | 5 +- .../leaderboard_screen.dart | 16 + .../video_details_screen.dart | 3 - .../video_details_view_model.dart | 1 + lib/src/widgets/controls_overlay.dart | 15 - pubspec.lock | 300 ++++++++++++++- pubspec.yaml | 3 + 27 files changed, 986 insertions(+), 212 deletions(-) create mode 100644 lib/src/models/hive_comments/request/hive_comments_request.g.dart create mode 100644 lib/src/models/hive_comments/response/active_vote.dart create mode 100644 lib/src/models/hive_comments/response/active_vote.g.dart create mode 100644 lib/src/models/hive_comments/response/hive_comment.dart create mode 100644 lib/src/models/hive_comments/response/hive_comment.g.dart create mode 100644 lib/src/models/hive_comments/response/hive_comments.g.dart create mode 100644 lib/src/models/home_screen_feed_models/home_feed_image.g.dart create mode 100644 lib/src/models/home_screen_feed_models/home_feed_models.g.dart create mode 100644 lib/src/models/leaderboard_models/leaderboard_models.dart create mode 100644 lib/src/models/video_details_model/video_details_description.g.dart create mode 100644 lib/src/screens/leaderboard_screen/leaderboard_screen.dart diff --git a/.flutter-plugins b/.flutter-plugins index 5ee678fe..7800a1de 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,6 +1,8 @@ # This is a generated file; do not edit or check into version control. firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/ firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/ -video_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/ +video_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.18/ +video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/ +video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/ video_player_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/ video_player_web_hls=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index df1f55d1..e5175d68 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_web"]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-03 00:06:03.139110","version":"2.8.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-04 23:18:28.756403","version":"2.8.1"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 6a2abd22..5ad96952 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -2,6 +2,20 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - + + + + + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 2d99f4f8..e13d2de3 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,11 +1,13 @@ - + + + - + diff --git a/.packages b/.packages index dfd0a3b0..a30233a9 100644 --- a/.packages +++ b/.packages @@ -3,47 +3,89 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-02-02 23:56:23.211792. +# Generated by pub on 2022-02-04 21:42:32.293399. +_fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-34.0.0/lib/ +analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.2.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ boolean_selector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/ +build:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build-2.2.1/lib/ +build_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_config-1.0.0/lib/ +build_daemon:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_daemon-3.0.1/lib/ +build_resolvers:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_resolvers-2.0.6/lib/ +build_runner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner-2.1.7/lib/ +build_runner_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner_core-7.2.3/lib/ +built_collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_collection-5.1.1/lib/ +built_value:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_value-8.1.4/lib/ characters:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib/ charcode:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib/ +checked_yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/checked_yaml-2.0.1/lib/ +cli_util:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cli_util-0.3.5/lib/ clock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib/ +code_builder:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/code_builder-4.1.0/lib/ collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0/lib/ +convert:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/convert-3.0.1/lib/ +crypto:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.1/lib/ csslib:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.17.1/lib/ +dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.1/lib/ fake_async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0/lib/ +file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib/ firebase_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/lib/ firebase_core_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_platform_interface-4.2.4/lib/ firebase_core_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/lib/ +fixnum:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fixnum-1.0.0/lib/ flutter:file:///Applications/flutter/flutter/packages/flutter/lib/ flutter_lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib/ flutter_markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_markdown-0.6.9/lib/ flutter_test:file:///Applications/flutter/flutter/packages/flutter_test/lib/ flutter_web_plugins:file:///Applications/flutter/flutter/packages/flutter_web_plugins/lib/ +frontend_server_client:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/frontend_server_client-2.1.2/lib/ +glob:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/glob-2.0.2/lib/ +graphs:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/graphs-2.1.0/lib/ html:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/html-0.15.0/lib/ http:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http-0.13.4/lib/ +http_multi_server:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_multi_server-3.0.1/lib/ http_parser:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_parser-4.0.0/lib/ +io:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/io-1.0.3/lib/ js:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3/lib/ +json_annotation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_annotation-4.4.0/lib/ +json_serializable:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_serializable-6.1.4/lib/ lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib/ +logging:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/logging-1.0.2/lib/ markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/markdown-4.0.1/lib/ matcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.11/lib/ meta:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib/ +mime:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/mime-1.0.1/lib/ +package_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_config-2.0.2/lib/ path:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.0/lib/ pedantic:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pedantic-1.11.1/lib/ plugin_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2/lib/ +pool:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pool-1.5.0/lib/ +pub_semver:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pub_semver-2.1.0/lib/ +pubspec_parse:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pubspec_parse-1.2.0/lib/ +shelf:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.2.0/lib/ +shelf_web_socket:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-1.0.1/lib/ sky_engine:file:///Applications/flutter/flutter/bin/cache/pkg/sky_engine/lib/ +source_gen:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_gen-1.2.1/lib/ +source_helper:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_helper-1.3.1/lib/ source_span:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.1/lib/ stack_trace:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib/ stream_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0/lib/ +stream_transform:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/stream_transform-2.0.0/lib/ string_scanner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib/ term_glyph:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0/lib/ test_api:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.3/lib/ -timeago:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timeago-3.1.0/lib/ +timeago:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timeago-3.2.1/lib/ +timing:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timing-1.0.0/lib/ typed_data:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib/ vector_math:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.1/lib/ -video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.15/lib/ +video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.18/lib/ +video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/lib/ +video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/lib/ video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-4.2.0/lib/ video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/lib/ video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/lib/ +watcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/watcher-1.0.1/lib/ +web_socket_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.1.0/lib/ +yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/yaml-3.1.0/lib/ acela:lib/ diff --git a/lib/src/models/hive_comments/request/hive_comments_request.dart b/lib/src/models/hive_comments/request/hive_comments_request.dart index 2244bcf4..afe9a7d0 100644 --- a/lib/src/models/hive_comments/request/hive_comments_request.dart +++ b/lib/src/models/hive_comments/request/hive_comments_request.dart @@ -1,24 +1,37 @@ import 'dart:convert'; +import 'package:json_annotation/json_annotation.dart'; -String hiveCommentsRequestToJson(HiveCommentsRequest data) => json.encode(data.toJson()); +part 'hive_comments_request.g.dart'; +String hiveCommentsRequestToJson(HiveCommentsRequest data) => + json.encode(data.toJson()); + +@JsonSerializable() class HiveCommentsRequest { - HiveCommentsRequest({required this.params}); + HiveCommentsRequest( + {required this.params, + required this.jsonrpc, + required this.method, + required this.id}); + List params; - var jsonrpc = "2.0"; - var method = "condenser_api.get_content_replies"; - var id = 1; - factory HiveCommentsRequest.from(String author, String permlink) { - return HiveCommentsRequest(params: [author, permlink]); - } + @JsonKey(defaultValue: "2.0") + String jsonrpc; - Map toJson() => { - "jsonrpc": jsonrpc, - "method": method, - "id": id, - "params": List.from(params.map((x) => x)), - }; -} + @JsonKey(defaultValue: "condenser_api.get_content_replies") + String method; -// {"jsonrpc":"2.0", "method":"condenser_api.get_content_replies", "params":["hiveio", "firstpost"], "id":1} \ No newline at end of file + @JsonKey(defaultValue: 1) + int id; + + Map toJson() => _$HiveCommentsRequestToJson(this); + + factory HiveCommentsRequest.from(String author, String permlink) { + return HiveCommentsRequest( + params: [author, permlink], + jsonrpc: "2.0", + method: "condenser_api.get_content_replies", + id: 1); + } +} \ No newline at end of file diff --git a/lib/src/models/hive_comments/request/hive_comments_request.g.dart b/lib/src/models/hive_comments/request/hive_comments_request.g.dart new file mode 100644 index 00000000..690c8cc9 --- /dev/null +++ b/lib/src/models/hive_comments/request/hive_comments_request.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'hive_comments_request.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +HiveCommentsRequest _$HiveCommentsRequestFromJson(Map json) => + HiveCommentsRequest( + params: + (json['params'] as List).map((e) => e as String).toList(), + jsonrpc: json['jsonrpc'] as String? ?? '2.0', + method: json['method'] as String? ?? 'condenser_api.get_content_replies', + id: json['id'] as int? ?? 1, + ); + +Map _$HiveCommentsRequestToJson( + HiveCommentsRequest instance) => + { + 'params': instance.params, + 'jsonrpc': instance.jsonrpc, + 'method': instance.method, + 'id': instance.id, + }; diff --git a/lib/src/models/hive_comments/response/active_vote.dart b/lib/src/models/hive_comments/response/active_vote.dart new file mode 100644 index 00000000..6114fe9f --- /dev/null +++ b/lib/src/models/hive_comments/response/active_vote.dart @@ -0,0 +1,19 @@ +import 'dart:convert'; +import 'package:json_annotation/json_annotation.dart'; + +part 'active_vote.g.dart'; + +ActiveVote activeVoteFromJson(String str) => + ActiveVote.fromJson(json.decode(str)); + +@JsonSerializable() +class ActiveVote { + ActiveVote({ + required this.percent, + }); + + int percent; + + factory ActiveVote.fromJson(Map json) => + _$ActiveVoteFromJson(json); +} diff --git a/lib/src/models/hive_comments/response/active_vote.g.dart b/lib/src/models/hive_comments/response/active_vote.g.dart new file mode 100644 index 00000000..a540c84f --- /dev/null +++ b/lib/src/models/hive_comments/response/active_vote.g.dart @@ -0,0 +1,16 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'active_vote.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ActiveVote _$ActiveVoteFromJson(Map json) => ActiveVote( + percent: json['percent'] as int, + ); + +Map _$ActiveVoteToJson(ActiveVote instance) => + { + 'percent': instance.percent, + }; diff --git a/lib/src/models/hive_comments/response/hive_comment.dart b/lib/src/models/hive_comments/response/hive_comment.dart new file mode 100644 index 00000000..92c8f049 --- /dev/null +++ b/lib/src/models/hive_comments/response/hive_comment.dart @@ -0,0 +1,34 @@ +import 'dart:convert'; +import 'active_vote.dart'; +import 'package:json_annotation/json_annotation.dart'; +part 'hive_comment.g.dart'; + +HiveComment hiveCommentFromJson(String str) => + HiveComment.fromJson(json.decode(str)); + +@JsonSerializable() +class HiveComment { + HiveComment({ + required this.author, + required this.permlink, + required this.body, + required this.created, + required this.depth, + required this.children, + required this.pendingPayoutValue, + required this.parentPermlink, + required this.activeVotes, + }); + + String author; + String permlink; + String body; + DateTime created; + int depth; + int children; + String pendingPayoutValue; + String parentPermlink; + List activeVotes; + + factory HiveComment.fromJson(Map json) => _$HiveCommentFromJson(json); +} \ No newline at end of file diff --git a/lib/src/models/hive_comments/response/hive_comment.g.dart b/lib/src/models/hive_comments/response/hive_comment.g.dart new file mode 100644 index 00000000..c79b0d88 --- /dev/null +++ b/lib/src/models/hive_comments/response/hive_comment.g.dart @@ -0,0 +1,34 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'hive_comment.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +HiveComment _$HiveCommentFromJson(Map json) => HiveComment( + author: json['author'] as String, + permlink: json['permlink'] as String, + body: json['body'] as String, + created: DateTime.parse(json['created'] as String), + depth: json['depth'] as int, + children: json['children'] as int, + pendingPayoutValue: json['pendingPayoutValue'] as String, + parentPermlink: json['parentPermlink'] as String, + activeVotes: (json['activeVotes'] as List) + .map((e) => ActiveVote.fromJson(e as Map)) + .toList(), + ); + +Map _$HiveCommentToJson(HiveComment instance) => + { + 'author': instance.author, + 'permlink': instance.permlink, + 'body': instance.body, + 'created': instance.created.toIso8601String(), + 'depth': instance.depth, + 'children': instance.children, + 'pendingPayoutValue': instance.pendingPayoutValue, + 'parentPermlink': instance.parentPermlink, + 'activeVotes': instance.activeVotes, + }; diff --git a/lib/src/models/hive_comments/response/hive_comments.dart b/lib/src/models/hive_comments/response/hive_comments.dart index aacadbb0..5ada0a85 100644 --- a/lib/src/models/hive_comments/response/hive_comments.dart +++ b/lib/src/models/hive_comments/response/hive_comments.dart @@ -3,12 +3,14 @@ // final hiveComments = hiveCommentsFromJson(jsonString); import 'dart:convert'; +import 'package:json_annotation/json_annotation.dart'; +import 'hive_comment.dart'; +part 'hive_comments.g.dart'; HiveComments hiveCommentsFromJson(String str) => HiveComments.fromJson(json.decode(str)); -String hiveCommentsToJson(HiveComments data) => json.encode(data.toJson()); - +@JsonSerializable() class HiveComments { HiveComments({ required this.result, @@ -16,77 +18,5 @@ class HiveComments { List result; - factory HiveComments.fromJson(Map json) => HiveComments( - result: - List.from(json["result"].map((x) => HiveComment.fromJson(x))), - ); - - Map toJson() => { - "result": List.from(result.map((x) => x.toJson())), - }; -} - -class HiveComment { - HiveComment({ - required this.author, - required this.permlink, - required this.body, - required this.created, - required this.depth, - required this.children, - required this.pendingPayoutValue, - required this.parentPermlink, - required this.activeVotes, - }); - - String author; - String permlink; - String body; - DateTime created; - int depth; - int children; - String pendingPayoutValue; - String parentPermlink; - List activeVotes; - - factory HiveComment.fromJson(Map json) => HiveComment( - author: json["author"], - permlink: json["permlink"], - body: json["body"], - created: DateTime.parse(json["created"]), - depth: json["depth"], - children: json["children"], - pendingPayoutValue: json["pending_payout_value"], - parentPermlink: json["parent_permlink"], - activeVotes: List.from( - json["active_votes"].map((x) => ActiveVote.fromJson(x))), - ); - - Map toJson() => { - "author": author, - "permlink": permlink, - "body": body, - "created": created.toIso8601String(), - "depth": depth, - "children": children, - "pending_payout_value": pendingPayoutValue, - "parent_permlink": parentPermlink, - "active_votes": List.from(activeVotes.map((x) => x.toJson())), - }; -} - -class ActiveVote { - ActiveVote({ - required this.percent, - }); - - int percent; - - factory ActiveVote.fromJson(Map json) => ActiveVote( - percent: json["percent"], - ); - - Map toJson() => { - "percent": percent, - }; + factory HiveComments.fromJson(Map json) => _$HiveCommentsFromJson(json); } diff --git a/lib/src/models/hive_comments/response/hive_comments.g.dart b/lib/src/models/hive_comments/response/hive_comments.g.dart new file mode 100644 index 00000000..6f5eab55 --- /dev/null +++ b/lib/src/models/hive_comments/response/hive_comments.g.dart @@ -0,0 +1,18 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'hive_comments.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +HiveComments _$HiveCommentsFromJson(Map json) => HiveComments( + result: (json['result'] as List) + .map((e) => HiveComment.fromJson(e as Map)) + .toList(), + ); + +Map _$HiveCommentsToJson(HiveComments instance) => + { + 'result': instance.result, + }; diff --git a/lib/src/models/home_screen_feed_models/home_feed_image.dart b/lib/src/models/home_screen_feed_models/home_feed_image.dart index fb049e67..c2b352d1 100644 --- a/lib/src/models/home_screen_feed_models/home_feed_image.dart +++ b/lib/src/models/home_screen_feed_models/home_feed_image.dart @@ -1,24 +1,15 @@ import 'dart:convert'; +import 'package:json_annotation/json_annotation.dart'; +part 'home_feed_image.g.dart'; HomeFeedImage homeFeedImageFromJson(String str) => HomeFeedImage.fromJson(json.decode(str)); -String homeFeedImageToJson(HomeFeedImage data) => json.encode(data.toJson()); - +@JsonSerializable() class HomeFeedImage { HomeFeedImage({ required this.thumbnail, }); String thumbnail; - factory HomeFeedImage.fromJson(Map json) { - final thumbnail = json['thumbnail'] as String?; - if (thumbnail == null) { - throw UnsupportedError('Invalid data: $json -> "thumbnail" is missing'); - } - return HomeFeedImage(thumbnail: thumbnail); - } - - Map toJson() => { - "thumbnail": thumbnail, - }; + factory HomeFeedImage.fromJson(Map json) => _$HomeFeedImageFromJson(json); } \ No newline at end of file diff --git a/lib/src/models/home_screen_feed_models/home_feed_image.g.dart b/lib/src/models/home_screen_feed_models/home_feed_image.g.dart new file mode 100644 index 00000000..a1e90eca --- /dev/null +++ b/lib/src/models/home_screen_feed_models/home_feed_image.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'home_feed_image.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +HomeFeedImage _$HomeFeedImageFromJson(Map json) => + HomeFeedImage( + thumbnail: json['thumbnail'] as String, + ); + +Map _$HomeFeedImageToJson(HomeFeedImage instance) => + { + 'thumbnail': instance.thumbnail, + }; diff --git a/lib/src/models/home_screen_feed_models/home_feed_models.dart b/lib/src/models/home_screen_feed_models/home_feed_models.dart index 3d3b219b..5229e2fd 100644 --- a/lib/src/models/home_screen_feed_models/home_feed_models.dart +++ b/lib/src/models/home_screen_feed_models/home_feed_models.dart @@ -1,26 +1,26 @@ import 'dart:convert'; - +import 'package:json_annotation/json_annotation.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed_image.dart'; +part 'home_feed_models.g.dart'; List homeFeedFromJson(String str) => List.from(json.decode(str).map((x) => HomeFeed.fromJson(x))); -String homeFeedToJson(List data) => json.encode(List.from(data.map((x) => x.toJson()))); - +@JsonSerializable() class HomeFeed { HomeFeed({ - required this.created, - required this.views, required this.author, required this.permlink, required this.title, required this.duration, required this.playUrl, required this.images, + this.created, + this.views, this.ipfs, }); - DateTime created; - int views; + DateTime? created; + int? views; String author; String permlink; String title; @@ -29,62 +29,5 @@ class HomeFeed { String playUrl; HomeFeedImage images; - factory HomeFeed.fromJson(Map json) { - final created = json['created'] as String?; - if (created == null) { - throw UnsupportedError('Invalid data: $json -> "created" is missing'); - } - final int? views = json['views'] as int?; - if (views == null) { - throw UnsupportedError('Invalid data: $json -> "views" is missing'); - } - final author = json['author'] as String?; - if (author == null) { - throw UnsupportedError('Invalid data: $json -> "author" is missing'); - } - final permlink = json['permlink'] as String?; - if (permlink == null) { - throw UnsupportedError('Invalid data: $json -> "permlink" is missing'); - } - final title = json['title'] as String?; - if (title == null) { - throw UnsupportedError('Invalid data: $json -> "title" is missing'); - } - final double? duration = double.parse(json['duration'].toString()); - if (duration == null) { - throw UnsupportedError('Invalid data: $json -> "duration" is missing'); - } - final playUrl = json['playUrl'] as String?; - if (playUrl == null) { - throw UnsupportedError('Invalid data: $json -> "playUrl" is missing'); - } - final images = json['images'] as Map?; - if (images == null) { - throw UnsupportedError('Invalid data: $json -> "images" is missing'); - } - final ipfs = json['ipfs'] as String?; - return HomeFeed( - created: DateTime.parse(created), - views: views, - author: author, - permlink: permlink, - title: title, - duration: duration, - ipfs: ipfs, - playUrl: playUrl, - images: HomeFeedImage.fromJson(images), - ); - } - - Map toJson() => { - "created": created.toIso8601String(), - "views": views, - "author": author, - "permlink": permlink, - "title": title, - "duration": duration, - "playUrl": playUrl, - "images": homeFeedImageToJson(images), - "ipfs": ipfs, - }; + factory HomeFeed.fromJson(Map json) => _$HomeFeedFromJson(json); } \ No newline at end of file diff --git a/lib/src/models/home_screen_feed_models/home_feed_models.g.dart b/lib/src/models/home_screen_feed_models/home_feed_models.g.dart new file mode 100644 index 00000000..141c2781 --- /dev/null +++ b/lib/src/models/home_screen_feed_models/home_feed_models.g.dart @@ -0,0 +1,33 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'home_feed_models.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +HomeFeed _$HomeFeedFromJson(Map json) => HomeFeed( + author: json['author'] as String, + permlink: json['permlink'] as String, + title: json['title'] as String, + duration: (json['duration'] as num).toDouble(), + playUrl: json['playUrl'] as String, + images: HomeFeedImage.fromJson(json['images'] as Map), + created: json['created'] == null + ? null + : DateTime.parse(json['created'] as String), + views: json['views'] as int?, + ipfs: json['ipfs'] as String?, + ); + +Map _$HomeFeedToJson(HomeFeed instance) => { + 'created': instance.created?.toIso8601String(), + 'views': instance.views, + 'author': instance.author, + 'permlink': instance.permlink, + 'title': instance.title, + 'duration': instance.duration, + 'ipfs': instance.ipfs, + 'playUrl': instance.playUrl, + 'images': instance.images, + }; diff --git a/lib/src/models/leaderboard_models/leaderboard_models.dart b/lib/src/models/leaderboard_models/leaderboard_models.dart new file mode 100644 index 00000000..e69de29b diff --git a/lib/src/models/video_details_model/video_details_description.dart b/lib/src/models/video_details_model/video_details_description.dart index f6bfaf6c..490151b1 100644 --- a/lib/src/models/video_details_model/video_details_description.dart +++ b/lib/src/models/video_details_model/video_details_description.dart @@ -1,9 +1,15 @@ import 'dart:convert'; +import 'package:json_annotation/json_annotation.dart'; -VideoDetailsDescription videoDetailsDescriptionFromJson(String str) => VideoDetailsDescription.fromJson(json.decode(str)); +part 'video_details_description.g.dart'; -String videoDetailsDescriptionToJson(VideoDetailsDescription data) => json.encode(data.toJson()); +VideoDetailsDescription videoDetailsDescriptionFromJson(String str) => + VideoDetailsDescription.fromJson(json.decode(str)); +String videoDetailsDescriptionToJson(VideoDetailsDescription data) => + json.encode(data.toJson()); + +@JsonSerializable() class VideoDetailsDescription { VideoDetailsDescription({ required this.description, @@ -11,11 +17,8 @@ class VideoDetailsDescription { String description; - factory VideoDetailsDescription.fromJson(Map json) => VideoDetailsDescription( - description: json["description"] ?? "", - ); + factory VideoDetailsDescription.fromJson(Map json) => + _$VideoDetailsDescriptionFromJson(json); - Map toJson() => { - "description": description, - }; -} \ No newline at end of file + Map toJson() => _$VideoDetailsDescriptionToJson(this); +} diff --git a/lib/src/models/video_details_model/video_details_description.g.dart b/lib/src/models/video_details_model/video_details_description.g.dart new file mode 100644 index 00000000..2a6fa8b8 --- /dev/null +++ b/lib/src/models/video_details_model/video_details_description.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'video_details_description.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +VideoDetailsDescription _$VideoDetailsDescriptionFromJson( + Map json) => + VideoDetailsDescription( + description: json['description'] as String, + ); + +Map _$VideoDetailsDescriptionToJson( + VideoDetailsDescription instance) => + { + 'description': instance.description, + }; diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index 0c17fd7b..830e6ff1 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -12,15 +12,16 @@ class HomeScreenWidgets { } Widget _tileTitle(HomeFeed item, BuildContext context) { - String timeInString = "📆 ${timeago.format(item.created)}"; + String timeInString = item.created != null ? "📆 ${timeago.format(item.created!)}" : ""; String owner = "👤 ${item.author}"; String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; + String views = item.views != null ? "▶ ${item.views!}" : ""; return ListTileVideo( placeholder: 'assets/branding/three_speak_logo.png', url: item.images.thumbnail, userThumbUrl: server.userOwnerThumb(item.author), title: item.title, - subtitle: "$timeInString $owner $duration ▶ ${item.views}", + subtitle: "$timeInString $owner $duration $views", ); } diff --git a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart new file mode 100644 index 00000000..f84ba4c5 --- /dev/null +++ b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; + +class LeaderboardScreen extends StatefulWidget { + const LeaderboardScreen({Key? key}) : super(key: key); + + @override + _LeaderboardScreenState createState() => _LeaderboardScreenState(); +} + +class _LeaderboardScreenState extends State { + + @override + Widget build(BuildContext context) { + return Container(); + } +} diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 690a94f6..9e28a446 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -34,9 +34,6 @@ class _VideoDetailsScreenState extends State { @override void initState() { - // String url = widget.vm.item.ipfs == null - // ? "https://threespeakvideo.b-cdn.net/${widget.vm.item.permlink}/default.m3u8" - // : "https://ipfs-3speak.b-cdn.net/ipfs/${widget.vm.item.ipfs}/default.m3u8"; controller = VideoPlayerController.network(widget.vm.item.playUrl) ..initialize().then((_) { setState(() { diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index 67be5ece..388470ae 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -1,4 +1,5 @@ import 'package:acela/src/models/hive_comments/request/hive_comments_request.dart'; +import 'package:acela/src/models/hive_comments/response/hive_comment.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed_models.dart'; import 'package:acela/src/models/video_details_model/video_details_description.dart'; diff --git a/lib/src/widgets/controls_overlay.dart b/lib/src/widgets/controls_overlay.dart index 08a0d483..b0a42ad1 100644 --- a/lib/src/widgets/controls_overlay.dart +++ b/lib/src/widgets/controls_overlay.dart @@ -5,26 +5,11 @@ class ControlsOverlay extends StatelessWidget { const ControlsOverlay({Key? key, required this.controller}) : super(key: key); - static const _exampleCaptionOffsets = [ - Duration(seconds: -10), - Duration(seconds: -3), - Duration(seconds: -1, milliseconds: -500), - Duration(milliseconds: -250), - Duration(milliseconds: 0), - Duration(milliseconds: 250), - Duration(seconds: 1, milliseconds: 500), - Duration(seconds: 3), - Duration(seconds: 10), - ]; static const _examplePlaybackRates = [ - 0.25, 0.5, 1.0, 1.5, 2.0, - 3.0, - 5.0, - 10.0, ]; final VideoPlayerController controller; diff --git a/pubspec.lock b/pubspec.lock index 556f6e06..d4eeada9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,20 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "34.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.0" args: dependency: transitive description: @@ -22,6 +36,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.1" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.6" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.7" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.2.3" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.1.4" characters: dependency: transitive description: @@ -36,6 +106,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" clock: dependency: transitive description: @@ -43,6 +127,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" collection: dependency: transitive description: @@ -50,6 +141,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" csslib: dependency: transitive description: @@ -57,6 +162,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.17.1" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.1" fake_async: dependency: transitive description: @@ -64,6 +176,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.2" firebase_core: dependency: "direct main" description: @@ -85,6 +204,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.5.4" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" flutter: dependency: "direct main" description: flutter @@ -114,6 +240,27 @@ packages: description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" html: dependency: transitive description: @@ -128,6 +275,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.13.4" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" http_parser: dependency: transitive description: @@ -135,6 +289,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" js: dependency: transitive description: @@ -142,6 +303,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.3" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.4.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.4" lints: dependency: transitive description: @@ -149,6 +324,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" markdown: dependency: transitive description: @@ -170,6 +352,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.7.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" path: dependency: transitive description: @@ -191,11 +387,60 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" source_span: dependency: transitive description: @@ -217,6 +462,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" string_scanner: dependency: transitive description: @@ -244,7 +496,14 @@ packages: name: timeago url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.2.1" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" typed_data: dependency: transitive description: @@ -265,7 +524,21 @@ packages: name: video_player url: "https://pub.dartlang.org" source: hosted - version: "2.2.15" + version: "2.2.18" + video_player_android: + dependency: transitive + description: + name: video_player_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.17" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.18" video_player_platform_interface: dependency: transitive description: @@ -287,6 +560,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.11+3" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" sdks: dart: ">=2.15.1 <3.0.0" - flutter: ">=2.5.0" + flutter: ">=2.8.0" diff --git a/pubspec.yaml b/pubspec.yaml index fae3b7e4..effd30c3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,7 @@ dependencies: sdk: flutter flutter_markdown: ^0.6.9 http: ^0.13.4 + json_annotation: ^4.4.0 timeago: ^3.1.0 video_player: ^2.2.14 video_player_web_hls: ^0.1.11+3 @@ -39,6 +40,8 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + build_runner: + json_serializable: # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is From 264a8f43e9a032fbc1ad47973409c5efd1edf9f3 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sat, 5 Feb 2022 23:58:26 +0530 Subject: [PATCH 009/466] leaderboard integrated --- .flutter-plugins-dependencies | 2 +- lib/main.dart | 5 ++ .../leaderboard_models/leaderboard_model.dart | 42 +++++++++++++ .../leaderboard_models.dart | 0 .../leaderboard_models/safe_convert.dart | 63 +++++++++++++++++++ .../screens/drawer_screen/drawer_screen.dart | 9 ++- .../leaderboard_screen.dart | 61 +++++++++++++++++- 7 files changed, 177 insertions(+), 5 deletions(-) create mode 100644 lib/src/models/leaderboard_models/leaderboard_model.dart delete mode 100644 lib/src/models/leaderboard_models/leaderboard_models.dart create mode 100644 lib/src/models/leaderboard_models/safe_convert.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index e5175d68..8ce43758 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-04 23:18:28.756403","version":"2.8.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-05 23:32:33.692222","version":"2.8.1"} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 3cc5ef24..1fb2bfeb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:acela/src/screens/home_screen/home_screen.dart'; +import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:firebase_core/firebase_core.dart'; @@ -90,6 +91,10 @@ class _MyAppState extends State { }); }); }); + } else if (settings.name == "/leaderboard") { + return MaterialPageRoute(builder: (context) { + return const LeaderboardScreen(); + }); } assert(false, 'Need to implement ${settings.name}'); return null; diff --git a/lib/src/models/leaderboard_models/leaderboard_model.dart b/lib/src/models/leaderboard_models/leaderboard_model.dart new file mode 100644 index 00000000..e708a061 --- /dev/null +++ b/lib/src/models/leaderboard_models/leaderboard_model.dart @@ -0,0 +1,42 @@ +import 'dart:convert'; +import 'safe_convert.dart'; + +// final jsonList = json.decode(jsonStr) as List; +// final list = jsonList.map((e) => LeaderboardResponseItem.fromJson(e)).toList(); + +List leaderboardResponseItemFromString(String string) { + final jsonList = json.decode(string) as List; + final list = + jsonList.map((e) => LeaderboardResponseItem.fromJson(e)).toList(); + return list; +} + +class LeaderboardResponseItem { + // 735 + final int rank; + + // 667.6 + final double score; + + // mrosenquist1 + final String username; + + LeaderboardResponseItem({ + this.rank = 0, + this.score = 0.0, + this.username = "", + }); + + factory LeaderboardResponseItem.fromJson(Map? json) => + LeaderboardResponseItem( + rank: asInt(json, 'rank'), + score: asDouble(json, 'score'), + username: asString(json, 'username'), + ); + + Map toJson() => { + 'rank': rank, + 'score': score, + 'username': username, + }; +} diff --git a/lib/src/models/leaderboard_models/leaderboard_models.dart b/lib/src/models/leaderboard_models/leaderboard_models.dart deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/src/models/leaderboard_models/safe_convert.dart b/lib/src/models/leaderboard_models/safe_convert.dart new file mode 100644 index 00000000..c2fc21f2 --- /dev/null +++ b/lib/src/models/leaderboard_models/safe_convert.dart @@ -0,0 +1,63 @@ + +int asInt(Map? json, String key, {int defaultValue = 0}) { + if (json == null || !json.containsKey(key)) return defaultValue; + var value = json[key]; + if (value == null) return defaultValue; + if (value is int) return value; + if (value is double) return value.toInt(); + if (value is bool) return value ? 1 : 0; + if (value is String) return int.tryParse(value) ?? double.tryParse(value)?.toInt() ?? defaultValue; + return defaultValue; +} + +double asDouble(Map? json, String key, {double defaultValue = 0.0}) { + if (json == null || !json.containsKey(key)) return defaultValue; + var value = json[key]; + if (value == null) return defaultValue; + if (value is double) return value; + if (value is int) return value.toDouble(); + if (value is bool) return value ? 1.0 : 0.0; + if (value is String) return double.tryParse(value) ?? defaultValue; + return defaultValue; +} + +bool asBool(Map? json, String key, {bool defaultValue = false}) { + if (json == null || !json.containsKey(key)) return defaultValue; + var value = json[key]; + if (value == null) return defaultValue; + if (value is bool) return value; + if (value is int) return value == 0 ? false : true; + if (value is double) return value == 0 ? false : true; + if (value is String) { + if (value == "1" || value.toLowerCase() == "true") return true; + if (value == "0" || value.toLowerCase() == "false") return false; + } + return defaultValue; +} + +String asString(Map? json, String key, {String defaultValue = ""}) { + if (json == null || !json.containsKey(key)) return defaultValue; + var value = json[key]; + if (value == null) return defaultValue; + if (value is String) return value; + if (value is int) return value.toString(); + if (value is double) return value.toString(); + if (value is bool) return value ? "true" : "false"; + return defaultValue; +} + +Map asMap(Map? json, String key, {Map? defaultValue}) { + if (json == null || !json.containsKey(key)) return defaultValue ?? {}; + var value = json[key]; + if (value == null) return defaultValue ?? {}; + if (value is Map) return value; + return defaultValue ?? {}; +} + +List asList(Map? json, String key, {List? defaultValue}) { + if (json == null || !json.containsKey(key)) return defaultValue ?? []; + var value = json[key]; + if (value == null) return defaultValue ?? []; + if (value is List) return value; + return defaultValue ?? []; +} diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 950a1d12..058c2938 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -56,11 +56,14 @@ class DrawerScreen extends StatelessWidget { ); } - Widget _leaderBoard() { + Widget _leaderBoard(BuildContext context) { return ListTile( leading: const Icon(Icons.leaderboard), title: const Text("Leaderboard"), - onTap: () {}, + onTap: () { + Navigator.pop(context); + Navigator.of(context).pushNamed("/leaderboard"); + }, ); } @@ -129,7 +132,7 @@ class DrawerScreen extends StatelessWidget { height: 1, color: Colors.blueGrey, ), - _leaderBoard(), + _leaderBoard(context), const Divider( height: 1, color: Colors.blueGrey, diff --git a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart index f84ba4c5..2b213e0a 100644 --- a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart +++ b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart @@ -1,4 +1,11 @@ +import 'dart:developer'; +import 'dart:core'; +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/leaderboard_models/leaderboard_model.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:acela/src/widgets/retry.dart'; import 'package:flutter/material.dart'; +import 'package:http/http.dart' show get; class LeaderboardScreen extends StatefulWidget { const LeaderboardScreen({Key? key}) : super(key: key); @@ -9,8 +16,60 @@ class LeaderboardScreen extends StatefulWidget { class _LeaderboardScreenState extends State { + Future> getData() async { + var response = await get(Uri.parse("${server.domain}/apiv2/leaderboard")); + if (response.statusCode == 200) { + return leaderboardResponseItemFromString(response.body); + } else { + throw "Status code not 200"; + } + } + + Widget _body() { + return FutureBuilder>( + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasError) { + return RetryScreen( + error: snapshot.error?.toString() ?? "Something went wrong", + onRetry: getData, + ); + } else if (snapshot.hasData) { + var data = snapshot.data!; + return ListView.separated(itemBuilder: (context, index) { + return ListTile( + leading: CircleAvatar(child: Image.network( + server.userOwnerThumb(data[index].username)),), + title: Text(data[index].username), + subtitle: Text( + "Rank: ${data[index].rank}\nScore: ${data[index].score}"), + onTap: () { + log("user tapped on ${data[index].username}"); + }, + ); + }, + separatorBuilder: (context, index) => const Divider(), + itemCount: data.length); + } else { + return RetryScreen( + error: "Something went wrong", + onRetry: getData, + ); + } + } else { + return const LoadingScreen(); + } + }, + future: getData()); + } + @override Widget build(BuildContext context) { - return Container(); + return Scaffold( + appBar: AppBar( + title: const Text("Leaderboard"), + ), + body: _body(), + ); } } From 3e73b4f718ee191f7c821701c64903d462b64de8 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 7 Feb 2022 02:26:50 +0530 Subject: [PATCH 010/466] new json parsing. new leaderboard --- .flutter-plugins-dependencies | 2 +- .../request/hive_comment_request.dart | 49 ++++++++ .../request/hive_comments_request.dart | 37 ------ .../request/hive_comments_request.g.dart | 25 ---- .../hive_comments/response/active_vote.dart | 49 ++++++-- .../hive_comments/response/active_vote.g.dart | 16 --- .../hive_comments/response/hive_comment.dart | 34 ------ .../response/hive_comment.g.dart | 34 ------ .../hive_comments/response/hive_comments.dart | 111 ++++++++++++++++-- .../response/hive_comments.g.dart | 18 --- .../home_screen_feed_models/home_feed.dart | 101 ++++++++++++++++ .../home_feed_image.dart | 15 --- .../home_feed_image.g.dart | 17 --- .../home_feed_models.dart | 33 ------ .../home_feed_models.g.dart | 33 ------ .../leaderboard_models/leaderboard_model.dart | 2 +- .../video_details_description.dart | 15 +-- .../video_details_description.g.dart | 19 --- lib/src/screens/home_screen/home_screen.dart | 4 +- .../home_screen/home_screen_view_model.dart | 7 +- .../home_screen/home_screen_widgets.dart | 14 +-- .../leaderboard_screen.dart | 92 ++++++++++++--- .../video_details_screen.dart | 4 +- .../video_details_view_model.dart | 15 ++- .../video_details_widgets.dart | 4 +- .../safe_convert.dart | 0 lib/src/widgets/custom_circle_avatar.dart | 1 + 27 files changed, 397 insertions(+), 354 deletions(-) create mode 100644 lib/src/models/hive_comments/request/hive_comment_request.dart delete mode 100644 lib/src/models/hive_comments/request/hive_comments_request.dart delete mode 100644 lib/src/models/hive_comments/request/hive_comments_request.g.dart delete mode 100644 lib/src/models/hive_comments/response/active_vote.g.dart delete mode 100644 lib/src/models/hive_comments/response/hive_comment.dart delete mode 100644 lib/src/models/hive_comments/response/hive_comment.g.dart delete mode 100644 lib/src/models/hive_comments/response/hive_comments.g.dart create mode 100644 lib/src/models/home_screen_feed_models/home_feed.dart delete mode 100644 lib/src/models/home_screen_feed_models/home_feed_image.dart delete mode 100644 lib/src/models/home_screen_feed_models/home_feed_image.g.dart delete mode 100644 lib/src/models/home_screen_feed_models/home_feed_models.dart delete mode 100644 lib/src/models/home_screen_feed_models/home_feed_models.g.dart delete mode 100644 lib/src/models/video_details_model/video_details_description.g.dart rename lib/src/{models/leaderboard_models => utils}/safe_convert.dart (100%) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 8ce43758..2a2d2148 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-05 23:32:33.692222","version":"2.8.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-07 02:16:02.062870","version":"2.8.1"} \ No newline at end of file diff --git a/lib/src/models/hive_comments/request/hive_comment_request.dart b/lib/src/models/hive_comments/request/hive_comment_request.dart new file mode 100644 index 00000000..5c4fe0d0 --- /dev/null +++ b/lib/src/models/hive_comments/request/hive_comment_request.dart @@ -0,0 +1,49 @@ +import 'package:acela/src/utils/safe_convert.dart'; +import 'dart:convert'; + +String hiveCommentRequestToJson(HiveCommentRequest data) => + json.encode(data.toJson()); + +class HiveCommentRequest { + final List params; + + // 2.0 + final String jsonrpc; + + // condenser_api.get_content_replies + final String method; + + // 1 + final int id; + + HiveCommentRequest({ + required this.params, + this.jsonrpc = "", + this.method = "", + this.id = 0, + }); + + factory HiveCommentRequest.from(List params) { + return HiveCommentRequest( + params: params, + method: "condenser_api.get_content_replies", + jsonrpc: "2.0", + id: 1, + ); + } + + factory HiveCommentRequest.fromJson(Map? json) => + HiveCommentRequest( + params: asList(json, 'params').map((e) => e.toString()).toList(), + jsonrpc: asString(json, 'jsonrpc'), + method: asString(json, 'method'), + id: asInt(json, 'id'), + ); + + Map toJson() => { + 'params': params.map((e) => e).toList(), + 'jsonrpc': jsonrpc, + 'method': method, + 'id': id, + }; +} diff --git a/lib/src/models/hive_comments/request/hive_comments_request.dart b/lib/src/models/hive_comments/request/hive_comments_request.dart deleted file mode 100644 index afe9a7d0..00000000 --- a/lib/src/models/hive_comments/request/hive_comments_request.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'dart:convert'; -import 'package:json_annotation/json_annotation.dart'; - -part 'hive_comments_request.g.dart'; - -String hiveCommentsRequestToJson(HiveCommentsRequest data) => - json.encode(data.toJson()); - -@JsonSerializable() -class HiveCommentsRequest { - HiveCommentsRequest( - {required this.params, - required this.jsonrpc, - required this.method, - required this.id}); - - List params; - - @JsonKey(defaultValue: "2.0") - String jsonrpc; - - @JsonKey(defaultValue: "condenser_api.get_content_replies") - String method; - - @JsonKey(defaultValue: 1) - int id; - - Map toJson() => _$HiveCommentsRequestToJson(this); - - factory HiveCommentsRequest.from(String author, String permlink) { - return HiveCommentsRequest( - params: [author, permlink], - jsonrpc: "2.0", - method: "condenser_api.get_content_replies", - id: 1); - } -} \ No newline at end of file diff --git a/lib/src/models/hive_comments/request/hive_comments_request.g.dart b/lib/src/models/hive_comments/request/hive_comments_request.g.dart deleted file mode 100644 index 690c8cc9..00000000 --- a/lib/src/models/hive_comments/request/hive_comments_request.g.dart +++ /dev/null @@ -1,25 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'hive_comments_request.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -HiveCommentsRequest _$HiveCommentsRequestFromJson(Map json) => - HiveCommentsRequest( - params: - (json['params'] as List).map((e) => e as String).toList(), - jsonrpc: json['jsonrpc'] as String? ?? '2.0', - method: json['method'] as String? ?? 'condenser_api.get_content_replies', - id: json['id'] as int? ?? 1, - ); - -Map _$HiveCommentsRequestToJson( - HiveCommentsRequest instance) => - { - 'params': instance.params, - 'jsonrpc': instance.jsonrpc, - 'method': instance.method, - 'id': instance.id, - }; diff --git a/lib/src/models/hive_comments/response/active_vote.dart b/lib/src/models/hive_comments/response/active_vote.dart index 6114fe9f..7b5122ae 100644 --- a/lib/src/models/hive_comments/response/active_vote.dart +++ b/lib/src/models/hive_comments/response/active_vote.dart @@ -1,19 +1,44 @@ -import 'dart:convert'; -import 'package:json_annotation/json_annotation.dart'; +import 'package:acela/src/utils/safe_convert.dart'; -part 'active_vote.g.dart'; - -ActiveVote activeVoteFromJson(String str) => - ActiveVote.fromJson(json.decode(str)); - -@JsonSerializable() class ActiveVote { + // 1000 + final int percent; + // 784865040553638 + final int reputation; + // 179995483613 + final int rshares; + // 2022-02-06T04:25:57 + final String time; + // jongolson + final String voter; + // 179995483613 + final int weight; + ActiveVote({ - required this.percent, + this.percent = 0, + this.reputation = 0, + this.rshares = 0, + this.time = "", + this.voter = "", + this.weight = 0, }); - int percent; + factory ActiveVote.fromJson(Map? json) => ActiveVote( + percent: asInt(json, 'percent'), + reputation: asInt(json, 'reputation'), + rshares: asInt(json, 'rshares'), + time: asString(json, 'time'), + voter: asString(json, 'voter'), + weight: asInt(json, 'weight'), + ); - factory ActiveVote.fromJson(Map json) => - _$ActiveVoteFromJson(json); + Map toJson() => { + 'percent': percent, + 'reputation': reputation, + 'rshares': rshares, + 'time': time, + 'voter': voter, + 'weight': weight, + }; } + diff --git a/lib/src/models/hive_comments/response/active_vote.g.dart b/lib/src/models/hive_comments/response/active_vote.g.dart deleted file mode 100644 index a540c84f..00000000 --- a/lib/src/models/hive_comments/response/active_vote.g.dart +++ /dev/null @@ -1,16 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'active_vote.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -ActiveVote _$ActiveVoteFromJson(Map json) => ActiveVote( - percent: json['percent'] as int, - ); - -Map _$ActiveVoteToJson(ActiveVote instance) => - { - 'percent': instance.percent, - }; diff --git a/lib/src/models/hive_comments/response/hive_comment.dart b/lib/src/models/hive_comments/response/hive_comment.dart deleted file mode 100644 index 92c8f049..00000000 --- a/lib/src/models/hive_comments/response/hive_comment.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'dart:convert'; -import 'active_vote.dart'; -import 'package:json_annotation/json_annotation.dart'; -part 'hive_comment.g.dart'; - -HiveComment hiveCommentFromJson(String str) => - HiveComment.fromJson(json.decode(str)); - -@JsonSerializable() -class HiveComment { - HiveComment({ - required this.author, - required this.permlink, - required this.body, - required this.created, - required this.depth, - required this.children, - required this.pendingPayoutValue, - required this.parentPermlink, - required this.activeVotes, - }); - - String author; - String permlink; - String body; - DateTime created; - int depth; - int children; - String pendingPayoutValue; - String parentPermlink; - List activeVotes; - - factory HiveComment.fromJson(Map json) => _$HiveCommentFromJson(json); -} \ No newline at end of file diff --git a/lib/src/models/hive_comments/response/hive_comment.g.dart b/lib/src/models/hive_comments/response/hive_comment.g.dart deleted file mode 100644 index c79b0d88..00000000 --- a/lib/src/models/hive_comments/response/hive_comment.g.dart +++ /dev/null @@ -1,34 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'hive_comment.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -HiveComment _$HiveCommentFromJson(Map json) => HiveComment( - author: json['author'] as String, - permlink: json['permlink'] as String, - body: json['body'] as String, - created: DateTime.parse(json['created'] as String), - depth: json['depth'] as int, - children: json['children'] as int, - pendingPayoutValue: json['pendingPayoutValue'] as String, - parentPermlink: json['parentPermlink'] as String, - activeVotes: (json['activeVotes'] as List) - .map((e) => ActiveVote.fromJson(e as Map)) - .toList(), - ); - -Map _$HiveCommentToJson(HiveComment instance) => - { - 'author': instance.author, - 'permlink': instance.permlink, - 'body': instance.body, - 'created': instance.created.toIso8601String(), - 'depth': instance.depth, - 'children': instance.children, - 'pendingPayoutValue': instance.pendingPayoutValue, - 'parentPermlink': instance.parentPermlink, - 'activeVotes': instance.activeVotes, - }; diff --git a/lib/src/models/hive_comments/response/hive_comments.dart b/lib/src/models/hive_comments/response/hive_comments.dart index 5ada0a85..f46e4d02 100644 --- a/lib/src/models/hive_comments/response/hive_comments.dart +++ b/lib/src/models/hive_comments/response/hive_comments.dart @@ -1,22 +1,109 @@ -// To parse this JSON data, do -// -// final hiveComments = hiveCommentsFromJson(jsonString); - +import 'package:acela/src/utils/safe_convert.dart'; +import 'active_vote.dart'; import 'dart:convert'; -import 'package:json_annotation/json_annotation.dart'; -import 'hive_comment.dart'; -part 'hive_comments.g.dart'; -HiveComments hiveCommentsFromJson(String str) => - HiveComments.fromJson(json.decode(str)); +HiveComments hiveCommentsFromString(String string) { + return HiveComments.fromJson(json.decode(string)); +} -@JsonSerializable() class HiveComments { + final String jsonrpc; + final List result; + final int id; + HiveComments({ + this.jsonrpc = "", required this.result, + this.id = 0, + }); + + factory HiveComments.fromJson(Map? json) => HiveComments( + jsonrpc: asString(json, 'jsonrpc'), + result: + asList(json, 'result').map((e) => HiveComment.fromJson(e)).toList(), + id: asInt(json, 'id'), + ); + + Map toJson() => { + 'jsonrpc': jsonrpc, + 'result': result.map((e) => e.toJson()), + 'id': id, + }; +} + +class HiveComment { + final String author; + final String permlink; + final String category; + final String body; + final String created; + final int depth; + final int children; + final String lastPayout; + final String cashoutTime; + final String totalPayoutValue; + final String curatorPayoutValue; + final String pendingPayoutValue; + final String parentAuthor; + final String parentPermlink; + final String url; + final List activeVotes; + + HiveComment({ + this.author = "", + this.permlink = "", + this.category = "", + this.body = "", + this.created = "", + this.depth = 0, + this.children = 0, + this.lastPayout = "", + this.cashoutTime = "", + this.totalPayoutValue = "", + this.curatorPayoutValue = "", + this.pendingPayoutValue = "", + this.parentAuthor = "", + this.parentPermlink = "", + this.url = "", + required this.activeVotes, }); - List result; + DateTime? get createdAt { + return DateTime.tryParse(created); + } + + factory HiveComment.fromJson(Map? json) => HiveComment( + author: asString(json, 'author'), + permlink: asString(json, 'permlink'), + category: asString(json, 'category'), + body: asString(json, 'body'), + created: asString(json, 'created'), + depth: asInt(json, 'depth'), + children: asInt(json, 'children'), + lastPayout: asString(json, 'last_payout'), + totalPayoutValue: asString(json, 'total_payout_value'), + pendingPayoutValue: asString(json, 'pending_payout_value'), + parentAuthor: asString(json, 'parent_author'), + parentPermlink: asString(json, 'parent_permlink'), + url: asString(json, 'url'), + activeVotes: asList(json, 'active_votes') + .map((e) => ActiveVote.fromJson(json)) + .toList(), + ); - factory HiveComments.fromJson(Map json) => _$HiveCommentsFromJson(json); + Map toJson() => { + 'author': author, + 'permlink': permlink, + 'category': category, + 'body': body, + 'created': created, + 'depth': depth, + 'children': children, + 'last_payout': lastPayout, + 'total_payout_value': totalPayoutValue, + 'pending_payout_value': pendingPayoutValue, + 'parent_author': parentAuthor, + 'url': url, + 'active_votes': activeVotes.map((e) => e), + }; } diff --git a/lib/src/models/hive_comments/response/hive_comments.g.dart b/lib/src/models/hive_comments/response/hive_comments.g.dart deleted file mode 100644 index 6f5eab55..00000000 --- a/lib/src/models/hive_comments/response/hive_comments.g.dart +++ /dev/null @@ -1,18 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'hive_comments.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -HiveComments _$HiveCommentsFromJson(Map json) => HiveComments( - result: (json['result'] as List) - .map((e) => HiveComment.fromJson(e as Map)) - .toList(), - ); - -Map _$HiveCommentsToJson(HiveComments instance) => - { - 'result': instance.result, - }; diff --git a/lib/src/models/home_screen_feed_models/home_feed.dart b/lib/src/models/home_screen_feed_models/home_feed.dart new file mode 100644 index 00000000..c68f3db7 --- /dev/null +++ b/lib/src/models/home_screen_feed_models/home_feed.dart @@ -0,0 +1,101 @@ +import 'dart:convert'; +import 'package:acela/src/utils/safe_convert.dart'; + +// final jsonList = json.decode(jsonStr) as List; +// final list = jsonList.map((e) => HomeFeedItem.fromJson(e)).toList(); + +List homeFeedItemFromString(String string) { + final jsonList = json.decode(string) as List; + final list = + jsonList.map((e) => HomeFeedItem.fromJson(e)).toList(); + return list; +} + +class HomeFeedItem { + final String created; + final String language; + final int views; + final String author; + final String permlink; + final String title; + final double duration; + final bool isNsfw; + final List tags; + final bool isIpfs; + final String playUrl; + final String ipfs; + final HomeFeedItemImage images; + + HomeFeedItem({ + this.created = "", + this.language = "", + this.views = 0, + this.author = "", + this.permlink = "", + this.title = "", + this.duration = 0.0, + this.isNsfw = false, + required this.tags, + this.isIpfs = false, + this.playUrl = "", + this.ipfs = "", + required this.images, + }); + + DateTime? get createdAt { + return DateTime.tryParse(created); + } + + factory HomeFeedItem.fromJson(Map? json) => HomeFeedItem( + created: asString(json, 'created'), + language: asString(json, 'language'), + views: asInt(json, 'views'), + author: asString(json, 'author'), + permlink: asString(json, 'permlink'), + title: asString(json, 'title'), + duration: asDouble(json, 'duration'), + isNsfw: asBool(json, 'isNsfw'), + tags: asList(json, 'tags').map((e) => e.toString()).toList(), + isIpfs: asBool(json, 'isIpfs'), + playUrl: asString(json, 'playUrl'), + ipfs: asString(json, 'ipfs'), + images: HomeFeedItemImage.fromJson(asMap(json, 'images')), + ); + + Map toJson() => { + 'created': created, + 'language': language, + 'views': views, + 'author': author, + 'permlink': permlink, + 'title': title, + 'duration': duration, + 'isNsfw': isNsfw, + 'tags': tags.map((e) => e), + 'isIpfs': isIpfs, + 'playUrl': playUrl, + 'ipfs': ipfs, + 'images': images.toJson(), + }; +} + +class HomeFeedItemImage { + final String ipfsThumbnail; + final String thumbnail; + + HomeFeedItemImage({ + this.ipfsThumbnail = "", + this.thumbnail = "", + }); + + factory HomeFeedItemImage.fromJson(Map? json) => HomeFeedItemImage( + ipfsThumbnail: asString(json, 'ipfs_thumbnail'), + thumbnail: asString(json, 'thumbnail'), + ); + + Map toJson() => { + 'ipfs_thumbnail': ipfsThumbnail, + 'thumbnail': thumbnail, + }; +} + diff --git a/lib/src/models/home_screen_feed_models/home_feed_image.dart b/lib/src/models/home_screen_feed_models/home_feed_image.dart deleted file mode 100644 index c2b352d1..00000000 --- a/lib/src/models/home_screen_feed_models/home_feed_image.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'dart:convert'; -import 'package:json_annotation/json_annotation.dart'; -part 'home_feed_image.g.dart'; - -HomeFeedImage homeFeedImageFromJson(String str) => HomeFeedImage.fromJson(json.decode(str)); - -@JsonSerializable() -class HomeFeedImage { - HomeFeedImage({ - required this.thumbnail, - }); - String thumbnail; - - factory HomeFeedImage.fromJson(Map json) => _$HomeFeedImageFromJson(json); -} \ No newline at end of file diff --git a/lib/src/models/home_screen_feed_models/home_feed_image.g.dart b/lib/src/models/home_screen_feed_models/home_feed_image.g.dart deleted file mode 100644 index a1e90eca..00000000 --- a/lib/src/models/home_screen_feed_models/home_feed_image.g.dart +++ /dev/null @@ -1,17 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'home_feed_image.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -HomeFeedImage _$HomeFeedImageFromJson(Map json) => - HomeFeedImage( - thumbnail: json['thumbnail'] as String, - ); - -Map _$HomeFeedImageToJson(HomeFeedImage instance) => - { - 'thumbnail': instance.thumbnail, - }; diff --git a/lib/src/models/home_screen_feed_models/home_feed_models.dart b/lib/src/models/home_screen_feed_models/home_feed_models.dart deleted file mode 100644 index 5229e2fd..00000000 --- a/lib/src/models/home_screen_feed_models/home_feed_models.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'dart:convert'; -import 'package:json_annotation/json_annotation.dart'; -import 'package:acela/src/models/home_screen_feed_models/home_feed_image.dart'; -part 'home_feed_models.g.dart'; - -List homeFeedFromJson(String str) => List.from(json.decode(str).map((x) => HomeFeed.fromJson(x))); - -@JsonSerializable() -class HomeFeed { - HomeFeed({ - required this.author, - required this.permlink, - required this.title, - required this.duration, - required this.playUrl, - required this.images, - this.created, - this.views, - this.ipfs, - }); - - DateTime? created; - int? views; - String author; - String permlink; - String title; - double duration; - String? ipfs; - String playUrl; - HomeFeedImage images; - - factory HomeFeed.fromJson(Map json) => _$HomeFeedFromJson(json); -} \ No newline at end of file diff --git a/lib/src/models/home_screen_feed_models/home_feed_models.g.dart b/lib/src/models/home_screen_feed_models/home_feed_models.g.dart deleted file mode 100644 index 141c2781..00000000 --- a/lib/src/models/home_screen_feed_models/home_feed_models.g.dart +++ /dev/null @@ -1,33 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'home_feed_models.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -HomeFeed _$HomeFeedFromJson(Map json) => HomeFeed( - author: json['author'] as String, - permlink: json['permlink'] as String, - title: json['title'] as String, - duration: (json['duration'] as num).toDouble(), - playUrl: json['playUrl'] as String, - images: HomeFeedImage.fromJson(json['images'] as Map), - created: json['created'] == null - ? null - : DateTime.parse(json['created'] as String), - views: json['views'] as int?, - ipfs: json['ipfs'] as String?, - ); - -Map _$HomeFeedToJson(HomeFeed instance) => { - 'created': instance.created?.toIso8601String(), - 'views': instance.views, - 'author': instance.author, - 'permlink': instance.permlink, - 'title': instance.title, - 'duration': instance.duration, - 'ipfs': instance.ipfs, - 'playUrl': instance.playUrl, - 'images': instance.images, - }; diff --git a/lib/src/models/leaderboard_models/leaderboard_model.dart b/lib/src/models/leaderboard_models/leaderboard_model.dart index e708a061..8c993c85 100644 --- a/lib/src/models/leaderboard_models/leaderboard_model.dart +++ b/lib/src/models/leaderboard_models/leaderboard_model.dart @@ -1,5 +1,5 @@ import 'dart:convert'; -import 'safe_convert.dart'; +import 'package:acela/src/utils/safe_convert.dart'; // final jsonList = json.decode(jsonStr) as List; // final list = jsonList.map((e) => LeaderboardResponseItem.fromJson(e)).toList(); diff --git a/lib/src/models/video_details_model/video_details_description.dart b/lib/src/models/video_details_model/video_details_description.dart index 490151b1..0983456d 100644 --- a/lib/src/models/video_details_model/video_details_description.dart +++ b/lib/src/models/video_details_model/video_details_description.dart @@ -1,7 +1,5 @@ import 'dart:convert'; -import 'package:json_annotation/json_annotation.dart'; - -part 'video_details_description.g.dart'; +import 'package:acela/src/utils/safe_convert.dart'; VideoDetailsDescription videoDetailsDescriptionFromJson(String str) => VideoDetailsDescription.fromJson(json.decode(str)); @@ -9,7 +7,6 @@ VideoDetailsDescription videoDetailsDescriptionFromJson(String str) => String videoDetailsDescriptionToJson(VideoDetailsDescription data) => json.encode(data.toJson()); -@JsonSerializable() class VideoDetailsDescription { VideoDetailsDescription({ required this.description, @@ -17,8 +14,12 @@ class VideoDetailsDescription { String description; - factory VideoDetailsDescription.fromJson(Map json) => - _$VideoDetailsDescriptionFromJson(json); + factory VideoDetailsDescription.fromJson(Map? json) => + VideoDetailsDescription( + description: asString(json, 'description'), + ); - Map toJson() => _$VideoDetailsDescriptionToJson(this); + Map toJson() => { + 'description': description + }; } diff --git a/lib/src/models/video_details_model/video_details_description.g.dart b/lib/src/models/video_details_model/video_details_description.g.dart deleted file mode 100644 index 2a6fa8b8..00000000 --- a/lib/src/models/video_details_model/video_details_description.g.dart +++ /dev/null @@ -1,19 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'video_details_description.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -VideoDetailsDescription _$VideoDetailsDescriptionFromJson( - Map json) => - VideoDetailsDescription( - description: json['description'] as String, - ); - -Map _$VideoDetailsDescriptionToJson( - VideoDetailsDescription instance) => - { - 'description': instance.description, - }; diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 86318281..0f00aceb 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -1,4 +1,4 @@ -import 'package:acela/src/models/home_screen_feed_models/home_feed_models.dart'; +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; @@ -40,7 +40,7 @@ class _HomeScreenState extends State { vm.loadHomeFeed(); } - void onTap(HomeFeed item) { + void onTap(HomeFeedItem item) { Navigator.of(context).pushNamed(VideoDetailsScreen.routeName, arguments: VideoDetailsScreenArguments(item)); } diff --git a/lib/src/screens/home_screen/home_screen_view_model.dart b/lib/src/screens/home_screen/home_screen_view_model.dart index 79b9486f..dce47cbf 100644 --- a/lib/src/screens/home_screen/home_screen_view_model.dart +++ b/lib/src/screens/home_screen/home_screen_view_model.dart @@ -1,6 +1,5 @@ +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:http/http.dart' show get; -import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/home_screen_feed_models/home_feed_models.dart'; enum LoadState { notStarted, @@ -11,7 +10,7 @@ enum LoadState { class HomeScreenViewModel { LoadState state = LoadState.notStarted; - List list = []; + List list = []; String error = 'Something went wrong'; Function() stateUpdated; @@ -23,7 +22,7 @@ class HomeScreenViewModel { stateUpdated(); var response = await get(Uri.parse(path)); if (response.statusCode == 200) { - List list = homeFeedFromJson(response.body); + List list = homeFeedItemFromString(response.body); state = LoadState.succeeded; this.list = list; stateUpdated(); diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index 830e6ff1..feb7962a 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -1,5 +1,5 @@ import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/home_screen_feed_models/home_feed_models.dart'; +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:acela/src/widgets/loading_screen.dart'; @@ -11,11 +11,11 @@ class HomeScreenWidgets { return const LoadingScreen(); } - Widget _tileTitle(HomeFeed item, BuildContext context) { - String timeInString = item.created != null ? "📆 ${timeago.format(item.created!)}" : ""; + Widget _tileTitle(HomeFeedItem item, BuildContext context) { + String timeInString = item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; String owner = "👤 ${item.author}"; String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; - String views = item.views != null ? "▶ ${item.views!}" : ""; + String views = "▶ ${item.views}"; return ListTileVideo( placeholder: 'assets/branding/three_speak_logo.png', url: item.images.thumbnail, @@ -26,7 +26,7 @@ class HomeScreenWidgets { } Widget _listTile( - HomeFeed item, BuildContext context, Function(HomeFeed) onTap) { + HomeFeedItem item, BuildContext context, Function(HomeFeedItem) onTap) { return ListTile( title: _tileTitle(item, context), onTap: () { @@ -35,8 +35,8 @@ class HomeScreenWidgets { ); } - Widget list(List list, Future Function() onRefresh, - Function(HomeFeed) onTap) { + Widget list(List list, Future Function() onRefresh, + Function(HomeFeedItem) onTap) { return Container( padding: const EdgeInsets.only(top: 10, bottom: 10), child: RefreshIndicator( diff --git a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart index 2b213e0a..e661b850 100644 --- a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart +++ b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart @@ -2,6 +2,7 @@ import 'dart:developer'; import 'dart:core'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/leaderboard_models/leaderboard_model.dart'; +import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/retry.dart'; import 'package:flutter/material.dart'; @@ -15,7 +16,6 @@ class LeaderboardScreen extends StatefulWidget { } class _LeaderboardScreenState extends State { - Future> getData() async { var response = await get(Uri.parse("${server.domain}/apiv2/leaderboard")); if (response.statusCode == 200) { @@ -25,6 +25,77 @@ class _LeaderboardScreenState extends State { } } + Widget _listTileSubtitle(LeaderboardResponseItem item) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Rank: ${item.rank}\nScore: ${item.score}"), + Container( + height: 5, + ), + LinearProgressIndicator( + value: item.score / 1000, + ) + ], + ); + } + + Widget _medalTile(LeaderboardResponseItem item, String medal) { + return ListTile( + leading: CustomCircleAvatar( + width: 60, + height: 60, + url: server.userOwnerThumb(item.username), + ), + title: Row( + children: [ + CircleAvatar( + child: Text(medal), + backgroundColor: Colors.transparent, + ), + const SizedBox( + width: 5, + ), + Text(item.username), + ], + ), + subtitle: _listTileSubtitle(item), + onTap: () { + log("user tapped on ${item.username}"); + }, + ); + } + + Widget _listTile(LeaderboardResponseItem item) { + return ListTile( + leading: CustomCircleAvatar( + width: 60, + height: 60, + url: server.userOwnerThumb(item.username), + ), + title: Text(item.username), + subtitle: _listTileSubtitle(item), + onTap: () { + log("user tapped on ${item.username}"); + }, + ); + } + + Widget _list(List data) { + return ListView.separated( + itemBuilder: (context, index) { + return index == 0 + ? _medalTile(data[index], '🥇') + : index == 1 + ? _medalTile(data[index], '🥈') + : index == 2 + ? _medalTile(data[index], '🥉') + : _listTile(data[index]); + }, + separatorBuilder: (context, index) => const Divider(), + itemCount: data.length); + } + Widget _body() { return FutureBuilder>( builder: (context, snapshot) { @@ -35,21 +106,10 @@ class _LeaderboardScreenState extends State { onRetry: getData, ); } else if (snapshot.hasData) { - var data = snapshot.data!; - return ListView.separated(itemBuilder: (context, index) { - return ListTile( - leading: CircleAvatar(child: Image.network( - server.userOwnerThumb(data[index].username)),), - title: Text(data[index].username), - subtitle: Text( - "Rank: ${data[index].rank}\nScore: ${data[index].score}"), - onTap: () { - log("user tapped on ${data[index].username}"); - }, - ); - }, - separatorBuilder: (context, index) => const Divider(), - itemCount: data.length); + return Container( + margin: const EdgeInsets.only(top: 10, bottom: 10), + child: _list(snapshot.data!.take(100).toList()), + ); } else { return RetryScreen( error: "Something went wrong", diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 9e28a446..d9bbfb3b 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -1,4 +1,4 @@ -import 'package:acela/src/models/home_screen_feed_models/home_feed_models.dart'; +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/screens/video_details_screen/video_details_widgets.dart'; import 'package:flutter/material.dart'; @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; class VideoDetailsScreenArguments { - final HomeFeed item; + final HomeFeedItem item; VideoDetailsScreenArguments(this.item); } diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index 388470ae..65b3a551 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -1,7 +1,6 @@ -import 'package:acela/src/models/hive_comments/request/hive_comments_request.dart'; -import 'package:acela/src/models/hive_comments/response/hive_comment.dart'; +import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; -import 'package:acela/src/models/home_screen_feed_models/home_feed_models.dart'; +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/video_details_model/video_details_description.dart'; import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; import 'package:http/http.dart' show get; @@ -15,7 +14,7 @@ class VideoDetailsViewModel { VideoDetailsDescription? description; // view - HomeFeed item; + HomeFeedItem item; // loading comments LoadState commentsState = LoadState.notStarted; @@ -50,12 +49,12 @@ class VideoDetailsViewModel { var client = http.Client(); var request = http.Request('POST', Uri.parse(server.hiveDomain)); request.body = - hiveCommentsRequestToJson(HiveCommentsRequest.from(author, permlink)); + hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); client .send(request) .then((response) => response.stream.bytesToString()) .then((value) { - HiveComments hiveComments = hiveCommentsFromJson(value); + HiveComments hiveComments = hiveCommentsFromString(value); commentsState = LoadState.succeeded; comments = hiveComments.result; stateUpdated(); @@ -71,12 +70,12 @@ class VideoDetailsViewModel { var client = http.Client(); var request = http.Request('POST', Uri.parse(server.hiveDomain)); request.body = - hiveCommentsRequestToJson(HiveCommentsRequest.from(author, permlink)); + hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); client .send(request) .then((response) => response.stream.bytesToString()) .then((value) { - HiveComments hiveComments = hiveCommentsFromJson(value); + HiveComments hiveComments = hiveCommentsFromString(value); comments.insertAll(index + 1, hiveComments.result); stateUpdated(); scanComments(stateUpdated); diff --git a/lib/src/screens/video_details_screen/video_details_widgets.dart b/lib/src/screens/video_details_screen/video_details_widgets.dart index c4e3b833..a714b7d0 100644 --- a/lib/src/screens/video_details_screen/video_details_widgets.dart +++ b/lib/src/screens/video_details_screen/video_details_widgets.dart @@ -90,7 +90,9 @@ class VideoDetailsScreenWidgets { var upVotes = item.activeVotes.where((e) => e.percent > 0).length; var downVotes = item.activeVotes.where((e) => e.percent < 0).length; var payout = item.pendingPayoutValue.replaceAll(" HBD", ""); - var timeInString = "📆 ${timeago.format(item.created)}"; + var timeInString = item.createdAt != null + ? "📆 ${timeago.format(item.createdAt!)}" + : ""; var text = "👤 $author 👍 $upVotes 👎 $downVotes 💰 $payout $timeInString"; var depth = (item.depth * 25.0) - 25; diff --git a/lib/src/models/leaderboard_models/safe_convert.dart b/lib/src/utils/safe_convert.dart similarity index 100% rename from lib/src/models/leaderboard_models/safe_convert.dart rename to lib/src/utils/safe_convert.dart diff --git a/lib/src/widgets/custom_circle_avatar.dart b/lib/src/widgets/custom_circle_avatar.dart index e8dfd9c6..52cff1e9 100644 --- a/lib/src/widgets/custom_circle_avatar.dart +++ b/lib/src/widgets/custom_circle_avatar.dart @@ -15,6 +15,7 @@ class CustomCircleAvatar extends StatelessWidget { width: width, child: CircleAvatar( backgroundImage: NetworkImage(url), + backgroundColor: Colors.transparent, radius: 100, ), ); From 673b5be81586073b1bab99dfc08334c6986ba5a9 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 8 Feb 2022 22:59:21 +0530 Subject: [PATCH 011/466] Fixing issues for web-app. Fixing issues for android-app. --- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 12 ++++- .packages | 5 ++- acela.iml | 6 +++ android/build.gradle | 2 +- ios/Podfile.lock | 10 ++--- lib/firebase_options.dart | 74 +++++++++++++++++++++++++++++++ lib/main.dart | 5 ++- pubspec.lock | 9 +++- 9 files changed, 112 insertions(+), 13 deletions(-) create mode 100644 lib/firebase_options.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 2a2d2148..784c3947 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-07 02:16:02.062870","version":"2.8.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-08 11:35:13.456761","version":"2.10.0"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 5ad96952..d07c8e25 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -352,6 +352,13 @@ + + + + + + @@ -495,7 +502,7 @@ - @@ -640,6 +647,7 @@ + @@ -659,7 +667,7 @@ - + diff --git a/.packages b/.packages index a30233a9..89e1dc7a 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-02-04 21:42:32.293399. +# Generated by pub on 2022-02-08 01:27:05.202770. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-34.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.2.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ @@ -54,6 +54,7 @@ lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/li logging:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/logging-1.0.2/lib/ markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/markdown-4.0.1/lib/ matcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.11/lib/ +material_color_utilities:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.3/lib/ meta:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib/ mime:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/mime-1.0.1/lib/ package_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_config-2.0.2/lib/ @@ -74,7 +75,7 @@ stream_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartla stream_transform:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/stream_transform-2.0.0/lib/ string_scanner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib/ term_glyph:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0/lib/ -test_api:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.3/lib/ +test_api:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.8/lib/ timeago:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timeago-3.2.1/lib/ timing:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timing-1.0.0/lib/ typed_data:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib/ diff --git a/acela.iml b/acela.iml index e252fd93..8c22ddee 100644 --- a/acela.iml +++ b/acela.iml @@ -60,6 +60,12 @@ + + + + + + diff --git a/android/build.gradle b/android/build.gradle index d302341a..7212d0dd 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.3.50' + ext.kotlin_version = '1.6.0' repositories { google() mavenCentral() diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 37b3f2d3..6ae4ff08 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -28,13 +28,13 @@ PODS: - nanopb/decode (2.30908.0) - nanopb/encode (2.30908.0) - PromisesObjC (2.0.0) - - video_player (0.0.1): + - video_player_avfoundation (0.0.1): - Flutter DEPENDENCIES: - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - Flutter (from `Flutter`) - - video_player (from `.symlinks/plugins/video_player/ios`) + - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) SPEC REPOS: trunk: @@ -51,8 +51,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/firebase_core/ios" Flutter: :path: Flutter - video_player: - :path: ".symlinks/plugins/video_player/ios" + video_player_avfoundation: + :path: ".symlinks/plugins/video_player_avfoundation/ios" SPEC CHECKSUMS: Firebase: 44dd9724c84df18b486639e874f31436eaa9a20c @@ -64,7 +64,7 @@ SPEC CHECKSUMS: GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 - video_player: ecd305f42e9044793efd34846e1ce64c31ea6fcb + video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff PODFILE CHECKSUM: 56099e53bf102df458f588dbe78632cd13d5357b diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart new file mode 100644 index 00000000..25f0b75e --- /dev/null +++ b/lib/firebase_options.dart @@ -0,0 +1,74 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + return web; + } + // ignore: missing_enum_constant_in_switch + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + return macos; + } + + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + + static const FirebaseOptions web = FirebaseOptions( + apiKey: 'AIzaSyCBelYnHytHyCdgeuS__jPnDMspMwUEL6c', + appId: '1:252548198943:web:6d5db0a3012636d0355b2a', + messagingSenderId: '252548198943', + projectId: 'acela-9c624', + authDomain: 'acela-9c624.firebaseapp.com', + storageBucket: 'acela-9c624.appspot.com', + measurementId: 'G-L9X49S2EG1', + ); + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyDZlrKYsD3jlvFkfiXPg3bbVjizqMUqSnE', + appId: '1:252548198943:android:ea163470c7c668c9355b2a', + messagingSenderId: '252548198943', + projectId: 'acela-9c624', + storageBucket: 'acela-9c624.appspot.com', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyBhRRZgrQb8WfCKVMjOwC4jnK0XiMuK4YM', + appId: '1:252548198943:ios:2fcda030e33a7164355b2a', + messagingSenderId: '252548198943', + projectId: 'acela-9c624', + storageBucket: 'acela-9c624.appspot.com', + iosClientId: '252548198943-ec3gnethnkvoudaat0lrobmq2t7mve8g.apps.googleusercontent.com', + iosBundleId: 'com.example.acela', + ); + + static const FirebaseOptions macos = FirebaseOptions( + apiKey: 'AIzaSyBhRRZgrQb8WfCKVMjOwC4jnK0XiMuK4YM', + appId: '1:252548198943:ios:2fcda030e33a7164355b2a', + messagingSenderId: '252548198943', + projectId: 'acela-9c624', + storageBucket: 'acela-9c624.appspot.com', + iosClientId: '252548198943-ec3gnethnkvoudaat0lrobmq2t7mve8g.apps.googleusercontent.com', + iosBundleId: 'com.example.acela', + ); +} diff --git a/lib/main.dart b/lib/main.dart index 1fb2bfeb..b1f432a5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,6 +4,7 @@ import 'package:acela/src/screens/video_details_screen/video_details_screen.dart import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; +import 'firebase_options.dart'; import 'src/bloc/server.dart'; @@ -20,7 +21,9 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - final Future _fbApp = Firebase.initializeApp(); + final Future _fbApp = Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform + ); bool isDarkMode = true; Widget futureBuilder(Widget withWidget) { diff --git a/pubspec.lock b/pubspec.lock index d4eeada9..67934e25 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -345,6 +345,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.3" meta: dependency: transitive description: @@ -489,7 +496,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.3" + version: "0.4.8" timeago: dependency: "direct main" description: From a56cf49b4ef66b03b598e0e0de87903e2542e7d4 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 10 Feb 2022 00:43:57 +0530 Subject: [PATCH 012/466] using future builder in video details. --- .firebase/hosting.YnVpbGQvd2Vi.cache | 16 ++ .firebase/hosting.d2Vi.cache | 11 ++ .firebaserc | 5 + .flutter-plugins-dependencies | 2 +- firebase.json | 16 ++ lib/main.dart | 12 +- .../video_details_model/video_details.dart | 112 +++++++++++ lib/src/screens/home_screen/home_screen.dart | 4 +- .../video_details_comments.dart | 125 ++++++++++++ .../video_details_screen.dart | 118 +++++++---- .../video_details_view_model.dart | 110 ++++------- .../video_details_widgets.dart | 184 ------------------ lib/src/widgets/video_player.dart | 53 +++++ 13 files changed, 461 insertions(+), 307 deletions(-) create mode 100644 .firebase/hosting.YnVpbGQvd2Vi.cache create mode 100644 .firebase/hosting.d2Vi.cache create mode 100644 .firebaserc create mode 100644 firebase.json create mode 100644 lib/src/models/video_details_model/video_details.dart create mode 100644 lib/src/screens/video_details_screen/video_details_comments.dart delete mode 100644 lib/src/screens/video_details_screen/video_details_widgets.dart create mode 100644 lib/src/widgets/video_player.dart diff --git a/.firebase/hosting.YnVpbGQvd2Vi.cache b/.firebase/hosting.YnVpbGQvd2Vi.cache new file mode 100644 index 00000000..444573c3 --- /dev/null +++ b/.firebase/hosting.YnVpbGQvd2Vi.cache @@ -0,0 +1,16 @@ +favicon.png,1643821544168,a9fd35ee7a0d03fa369740142b0eadc6d794c7d94a3112a7d8fa5e1b9b00fe3f +manifest.json,1643216912520,3b0da3b3b92dc0328b324ad0ad828f08f0d6807cb949b36f0ec722861759aacb +icons/Icon-192.png,1643821604698,4513a7b0bac37d1b6677f27b87f25c5f6f2dbcdad12ef49f43c1173788edd56d +icons/Icon-512.png,1643821631249,1e65fd7dc5ed1eaab6aae9fd5a18542a1ee5baabd0f52c094c62f3595aa00af5 +icons/Icon-maskable-192.png,1643821689292,3a402c33b814408a1d4e91f1e7afab7b85b76247bc9fd735eb2007273008f5c6 +icons/Icon-maskable-512.png,1643821670987,1a3f03a5d284c1bea6032c4bd42cc29f66504ada5351e1b161d8626af2f02c33 +flutter_service_worker.js,1644342899216,71536c7b0dcea8f23e015cd2ba090f7de598c0fee6c44e6c7e2af8ebf091c3c6 +index.html,1644342899117,2d954e87d5a7aab731258ff5e631a592272f763155dc2019d4fccc10137cbd6d +assets/AssetManifest.json,1644342899110,0b95630463cd2782488987ad923759f47cc68f73214c391ade6944d7a27c7560 +assets/FontManifest.json,1644342899110,2a26cf55926df210ccb9d713372cb114e0a12bf97104f6833e382566e2e7b16e +version.json,1644342899015,0a47060cfa5ce3c6a31fc65b7b255084deb121b4698df6016d27e58cb5cd20fc +assets/assets/branding/three_speak_icon.png,1643216912507,2d8407594c7d199c572113bc3de8a90d268d7b791a86573ee237ca1af71148ca +assets/assets/branding/three_speak_logo.png,1643216912507,3ac2dbaa31235a5df9a7b984903728f8d524eebcaedc9e9312fe69cc569b3700 +assets/NOTICES,1644342899110,c1ca890cf2497ad99773292837197c505ca33416e4d06dc7b5ae83ad22dd11b5 +assets/fonts/MaterialIcons-Regular.otf,1615596762000,5f71a8843e4edc9656c39061c2232458a6fc77e1603305960e4efa9c77f8b7a2 +main.dart.js,1644342898796,e39a78595db0afd7fe60932fc8685684440913b5519c6d532f4329cd472f6acc diff --git a/.firebase/hosting.d2Vi.cache b/.firebase/hosting.d2Vi.cache new file mode 100644 index 00000000..2bc282db --- /dev/null +++ b/.firebase/hosting.d2Vi.cache @@ -0,0 +1,11 @@ +index.html,1644298698913,90872ebed15c4e53f235e21f25c3ee9673cf1703821f3a20a0538baef89477b1 +flutter_service_worker.js,1644298699081,a0f8cb4a314c0a1f2bf6aaf37d35a4f8da8771d81ee9c1ab9b323bb9931a4979 +version.json,1644298698781,0a47060cfa5ce3c6a31fc65b7b255084deb121b4698df6016d27e58cb5cd20fc +favicon.png,1643821544168,a9fd35ee7a0d03fa369740142b0eadc6d794c7d94a3112a7d8fa5e1b9b00fe3f +manifest.json,1643216912520,3b0da3b3b92dc0328b324ad0ad828f08f0d6807cb949b36f0ec722861759aacb +public/index.html,1644298775473,46ade53fbfcbdb41812cd4f43fec88f503bcec13e40424a3ab140e407bb4a797 +icons/Icon-192.png,1643821604698,4513a7b0bac37d1b6677f27b87f25c5f6f2dbcdad12ef49f43c1173788edd56d +icons/Icon-maskable-192.png,1643821689292,3a402c33b814408a1d4e91f1e7afab7b85b76247bc9fd735eb2007273008f5c6 +icons/Icon-512.png,1643821631249,1e65fd7dc5ed1eaab6aae9fd5a18542a1ee5baabd0f52c094c62f3595aa00af5 +icons/Icon-maskable-512.png,1643821670987,1a3f03a5d284c1bea6032c4bd42cc29f66504ada5351e1b161d8626af2f02c33 +main.dart.js,1644298663032,d8da587ee0cae26f74d98059eeaae09db436a924296648fa119ad27913ffbc92 diff --git a/.firebaserc b/.firebaserc new file mode 100644 index 00000000..66e94a20 --- /dev/null +++ b/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "acela-9c624" + } +} diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 784c3947..c6c8af1b 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-08 11:35:13.456761","version":"2.10.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-10 00:38:24.036116","version":"2.10.0"} \ No newline at end of file diff --git a/firebase.json b/firebase.json new file mode 100644 index 00000000..66037326 --- /dev/null +++ b/firebase.json @@ -0,0 +1,16 @@ +{ + "hosting": { + "public": "build/web", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } +} diff --git a/lib/main.dart b/lib/main.dart index b1f432a5..4fec279d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,7 +10,7 @@ import 'src/bloc/server.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(MyApp()); + runApp(const MyApp()); } class MyApp extends StatefulWidget { @@ -21,9 +21,8 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - final Future _fbApp = Firebase.initializeApp( - options: DefaultFirebaseOptions.currentPlatform - ); + final Future _fbApp = + Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); bool isDarkMode = true; Widget futureBuilder(Widget withWidget) { @@ -48,11 +47,10 @@ class _MyAppState extends State { theme: isDarkMode ? ThemeData.dark() : ThemeData.light(), debugShowCheckedModeBanner: false, onGenerateRoute: (settings) { - if (settings.name == VideoDetailsScreen.routeName) { - final args = settings.arguments as VideoDetailsScreenArguments; + if (settings.name?.contains("/watch?") == true) { return MaterialPageRoute(builder: (context) { return VideoDetailsScreen( - vm: VideoDetailsViewModel(item: args.item)); + vm: VideoDetailsViewModel.from(settings.name!)); }); } else if (settings.name == "/") { return MaterialPageRoute(builder: (context) { diff --git a/lib/src/models/video_details_model/video_details.dart b/lib/src/models/video_details_model/video_details.dart new file mode 100644 index 00000000..343355e2 --- /dev/null +++ b/lib/src/models/video_details_model/video_details.dart @@ -0,0 +1,112 @@ +import 'dart:convert'; +import 'package:acela/src/utils/safe_convert.dart'; + +VideoDetails videoDetailsFromJson(String str) => + VideoDetails.fromJson(json.decode(str)); + +String videoDetailsToJson(VideoDetails data) => json.encode(data.toJson()); + +class VideoDetails { + // 2022-02-08T19:17:10.065Z + final String created; + + // false + final bool paid; + + // 5 + final int views; + final List tagsV2; + + // 6202bef63df91fd29d7cbd2d + final String id; + + // iOS Development + final String community; + + // gqbffyah + final String permlink; + + // 203.333333 + final double duration; + + // 98062751 + final int size; + + // sagarkothari88 + final String owner; + + // URL - https://acela-9c624.web.app/### What did I do?* Research & Experiments for * iOS App Deployment * Android App Deployment * Web-app Deployment* Deployed web-app on firebase hosting* Why App as an web-app? * With the features we've built - It's 99% same experience for web-app or app. * For now, we're deploying it as web-app so that we do not have to worry about Apple's approval process or Google's Play Store approval process.### What's next?* User's Channel Home page### Previous UpdatesIf you've not checked my previous videos, please check those.* Updates in 3 mins - 3Speak.tv app for iOS, Android & Web * https://3speak.tv/watch?v=sagarkothari88/nzvezwzc* Updates in 5 mins - 3Speak.tv App for iOS, Android & Web * https://3speak.tv/watch?v=sagarkothari88/hawmmhlq* How do I install 3Speak.tv app on my Android Device? * https://3speak.tv/watch?v=sagarkothari88/xtdlszgb* 3Speak App Update * https://3speak.tv/watch?v=sagarkothari88/mfmakjwp* 3Speak App Update * https://3speak.tv/watch?v=sagarkothari88/canucyoa* iOS App Update in 6 mins * https://3speak.tv/watch?v=sagarkothari88/bfvgzkkl* iOS App Update in 3 mins * https://3speak.tv/watch?v=sagarkothari88/xtlyduch* iOS App Update in 2 mins * https://3speak.tv/watch?v=sagarkothari88/iwdnghrnPlease please please up-vote my videos to keep me motivated. + final String description; + + // ipfs://bafybeieh2ylatpwqaoah7ztbwwj43bm3v3v76ymb732tkzxyr4fq4ea3aq + final String thumbnail; + + // How do I install app on my iPhone or on my Android? + final String title; + + // https://images.hive.blog/p/99pyU5Ga1kwr5bsMXthzYLbcngN4W2P8NtU9TWTdHC3HaQbjuuRfKKVdjVfWMw2cQWSAejpKRAqR2gj56yBNVYN6UkvLX7djqZAu5a3HuWPbdhvhtLqLkUTqPszx6T1CMU?format=jpeg&mode=cover&width=340&height=191 + final String thumbUrl; + + // https://ipfs-3speak.b-cdn.net/ipfs/bafybeieh2ylatpwqaoah7ztbwwj43bm3v3v76ymb732tkzxyr4fq4ea3aq/ + final String baseThumbUrl; + + // https://threespeakvideo.b-cdn.net/gqbffyah/default.m3u8 + final String playUrl; + + VideoDetails({ + this.created = "", + this.paid = false, + this.views = 0, + required this.tagsV2, + this.id = "", + this.community = "", + this.permlink = "", + this.duration = 0.0, + this.size = 0, + this.owner = "", + this.description = "", + this.thumbnail = "", + this.title = "", + this.thumbUrl = "", + this.baseThumbUrl = "", + this.playUrl = "", + }); + + factory VideoDetails.fromJson(Map? json) => VideoDetails( + created: asString(json, 'created'), + paid: asBool(json, 'paid'), + views: asInt(json, 'views'), + tagsV2: asList(json, 'tags_v2').map((e) => e.toString()).toList(), + id: asString(json, '_id'), + community: asString(json, 'community'), + permlink: asString(json, 'permlink'), + duration: asDouble(json, 'duration'), + size: asInt(json, 'size'), + owner: asString(json, 'owner'), + description: asString(json, 'description'), + thumbnail: asString(json, 'thumbnail'), + title: asString(json, 'title'), + thumbUrl: asString(json, 'thumbUrl'), + baseThumbUrl: asString(json, 'baseThumbUrl'), + playUrl: asString(json, 'playUrl'), + ); + + Map toJson() => { + 'created': created, + 'paid': paid, + 'views': views, + 'tags_v2': tagsV2.map((e) => e), + '_id': id, + 'community': community, + 'permlink': permlink, + 'duration': duration, + 'size': size, + 'owner': owner, + 'description': description, + 'thumbnail': thumbnail, + 'title': title, + 'thumbUrl': thumbUrl, + 'baseThumbUrl': baseThumbUrl, + 'playUrl': playUrl, + }; +} diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 0f00aceb..1f4fdaf7 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -41,8 +41,8 @@ class _HomeScreenState extends State { } void onTap(HomeFeedItem item) { - Navigator.of(context).pushNamed(VideoDetailsScreen.routeName, - arguments: VideoDetailsScreenArguments(item)); + Navigator.of(context).pushNamed( + VideoDetailsScreen.routeName(item.author, item.permlink)); } Widget _screen() { diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart new file mode 100644 index 00000000..0da454eb --- /dev/null +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -0,0 +1,125 @@ +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart'; +import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; +import 'package:acela/src/widgets/custom_circle_avatar.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:http/http.dart' as http; +import 'package:timeago/timeago.dart' as timeago; + +class VideoDetailsCommentsWidget extends StatefulWidget { + const VideoDetailsCommentsWidget( + {Key? key, required this.author, required this.permlink}) + : super(key: key); + final String author; + final String permlink; + + @override + _VideoDetailsCommentsWidgetState createState() => + _VideoDetailsCommentsWidgetState(); +} + +class _VideoDetailsCommentsWidgetState + extends State { + Future> loadComments(String author, String permlink) async { + var client = http.Client(); + var body = + hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); + var response = await client.post(Uri.parse(server.hiveDomain), body: body); + if (response.statusCode == 200) { + var hiveCommentsResponse = hiveCommentsFromString(response.body); + var comments = hiveCommentsResponse.result; + for (var i = 0; i < comments.length; i++) { + if (comments[i].children > 0) { + if (comments + .where((e) => e.parentPermlink == comments[i].permlink) + .isEmpty) { + var newComments = + await loadComments(comments[i].author, comments[i].permlink); + comments.insertAll(i + 1, newComments); + } + } + } + return comments; + } else { + throw "Status code is ${response.statusCode}"; + } + } + + Widget listTile(HiveComment comment) { + var item = comment; + var userThumb = server.userOwnerThumb(item.author); + var author = item.author; + var body = item.body; + var upVotes = item.activeVotes.where((e) => e.percent > 0).length; + var downVotes = item.activeVotes.where((e) => e.percent < 0).length; + var payout = item.pendingPayoutValue.replaceAll(" HBD", ""); + var timeInString = + item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; + var text = + "👤 $author 👍 $upVotes 👎 $downVotes 💰 $payout $timeInString"; + var depth = (item.depth * 25.0) - 25; + double width = MediaQuery.of(context).size.width - 70 - depth; + return ListTile( + title: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container(margin: EdgeInsets.only(left: depth)), + CustomCircleAvatar(height: 25, width: 25, url: userThumb), + Container(margin: const EdgeInsets.only(right: 10)), + SizedBox( + width: width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MarkdownBody( + data: body, + shrinkWrap: true, + ), + Container(margin: const EdgeInsets.only(bottom: 10)), + Text( + text, + style: Theme.of(context).textTheme.bodyText1, + ), + ], + ), + ) + ], + ), + onTap: () { + print("Tapped"); + }, + ); + } + + Widget commentsListView(List comments) { + return ListView.separated( + itemBuilder: (context, index) { + return listTile(comments[index]); + }, + separatorBuilder: (context, index) => const Divider( + height: 10, + color: Colors.blueGrey, + ), + itemCount: comments.length); + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: loadComments(widget.author, widget.permlink), + builder: (builder, snapshot) { + if (snapshot.hasError) { + String text = + 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; + return Text(text); + } else if (snapshot.hasData) { + var data = snapshot.data! as List; + return commentsListView(data); + } else { + return const LoadingScreen(); + } + }); + } +} diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index d9bbfb3b..dff75903 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -1,63 +1,103 @@ -import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/video_details_model/video_details.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_widgets.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:acela/src/widgets/video_player.dart'; import 'package:flutter/material.dart'; -// import 'package:better_player/better_player.dart'; - -import 'package:video_player/video_player.dart'; - -class VideoDetailsScreenArguments { - final HomeFeedItem item; - - VideoDetailsScreenArguments(this.item); -} +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:http/http.dart'; class VideoDetailsScreen extends StatefulWidget { const VideoDetailsScreen({Key? key, required this.vm}) : super(key: key); final VideoDetailsViewModel vm; - static const routeName = '/video_details'; + static String routeName(String owner, String permLink) { + return '/watch?owner=$owner&permlink=$permLink'; + } @override _VideoDetailsScreenState createState() => _VideoDetailsScreenState(); } class _VideoDetailsScreenState extends State { - final widgets = VideoDetailsScreenWidgets(); - late VideoPlayerController controller; + static const List tabs = [ + Tab(text: 'Video'), + Tab(text: 'Description'), + Tab(text: 'Comments') + ]; - @override - void dispose() { - super.dispose(); - controller.dispose(); + Future getVideoDetails() async { + final endPoint = + "${server.domain}/apiv2/@${widget.vm.author}/${widget.vm.permlink}"; + var response = await get(Uri.parse(endPoint)); + if (response.statusCode == 200) { + VideoDetails data = videoDetailsFromJson(response.body); + return data; + } else { + throw "Status code = ${response.statusCode}"; + } } - @override - void initState() { - controller = VideoPlayerController.network(widget.vm.item.playUrl) - ..initialize().then((_) { - setState(() { - controller.play(); - }); - }); - super.initState(); + Widget container(String title, Widget body) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + body: body, + ); } - void initViewModel(BuildContext context) { - widget.vm.loadVideoInfo(() { - setState(() {}); - }); - widget.vm.loadComments(widget.vm.item.author, widget.vm.item.permlink, () { - setState(() {}); - }); + Widget descriptionMarkDown(String markDown) { + return Container( + margin: const EdgeInsets.all(10), + child: Markdown( + data: markDown, + ), + ); + } + + Widget tabBar(VideoDetails details) { + return DefaultTabController( + length: tabs.length, + child: Builder( + builder: (context) { + return Scaffold( + appBar: AppBar( + title: Text(details.title), + bottom: const TabBar(tabs: tabs), + ), + body: TabBarView( + children: [ + SPKVideoPlayer( + playUrl: details.playUrl, + ), + descriptionMarkDown(details.description), + VideoDetailsCommentsWidget( + author: details.owner, permlink: details.permlink), + ], + ), + ); + }, + ), + ); } @override Widget build(BuildContext context) { - initViewModel(context); - Widget videoView = widgets.getPlayer(context, controller); - return widgets.tabBar(context, videoView, widget.vm, () { - setState(() {}); - }); + return FutureBuilder( + future: getVideoDetails(), + builder: (builder, snapshot) { + if (snapshot.hasError) { + String text = + 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; + return container(widget.vm.author, Text(text)); + } else if (snapshot.hasData) { + var data = snapshot.data! as VideoDetails; + return tabBar(data); + } else { + return container(widget.vm.author, const LoadingScreen()); + } + }); } } diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index 65b3a551..383f3061 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -1,6 +1,5 @@ import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; -import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/video_details_model/video_details_description.dart'; import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; import 'package:http/http.dart' show get; @@ -14,86 +13,49 @@ class VideoDetailsViewModel { VideoDetailsDescription? description; // view - HomeFeedItem item; + String path; + String author; + String permlink; // loading comments LoadState commentsState = LoadState.notStarted; String commentsError = 'Something went wrong'; List comments = []; - VideoDetailsViewModel({required this.item}); + VideoDetailsViewModel( + {required this.path, required this.author, required this.permlink}); - void loadVideoInfo(Function stateUpdated) { - if (descState != LoadState.notStarted) return; - descState = LoadState.loading; - stateUpdated(); - final endPoint = "${server.domain}/apiv2/@${item.author}/${item.permlink}"; - get(Uri.parse(endPoint)) - .then((response) { - VideoDetailsDescription desc = - videoDetailsDescriptionFromJson(response.body); - descState = LoadState.succeeded; - description = desc; - stateUpdated(); - }).catchError((error) { - descError = - 'Something went wrong.\nError is $error'; - descState = LoadState.failed; - stateUpdated(); - }); - } - - void loadComments(String author, String permlink, Function stateUpdated) { - if (commentsState != LoadState.notStarted) return; - commentsState = LoadState.loading; - var client = http.Client(); - var request = http.Request('POST', Uri.parse(server.hiveDomain)); - request.body = - hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); - client - .send(request) - .then((response) => response.stream.bytesToString()) - .then((value) { - HiveComments hiveComments = hiveCommentsFromString(value); - commentsState = LoadState.succeeded; - comments = hiveComments.result; - stateUpdated(); - scanComments(stateUpdated); - }).catchError((error) { - commentsError = 'Something went wrong.\nError is $error'; - commentsState = LoadState.failed; - stateUpdated(); - }); - } - - void childrenComments(String author, String permlink, int index, Function stateUpdated) { - var client = http.Client(); - var request = http.Request('POST', Uri.parse(server.hiveDomain)); - request.body = - hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); - client - .send(request) - .then((response) => response.stream.bytesToString()) - .then((value) { - HiveComments hiveComments = hiveCommentsFromString(value); - comments.insertAll(index + 1, hiveComments.result); - stateUpdated(); - scanComments(stateUpdated); - }).catchError((error) { - // commentsError = 'Something went wrong.\nError is $error'; - // commentsState = LoadState.failed; - // stateUpdated(); - }); - } - - void scanComments(Function stateUpdated) { - for(var i=0; i < comments.length; i++) { - if (comments[i].children > 0) { - if (comments.where((e) => e.parentPermlink == comments[i].permlink).isEmpty) { - childrenComments(comments[i].author, comments[i].permlink, i, stateUpdated); - break; - } - } + factory VideoDetailsViewModel.from(String path) { + if (!path.contains("owner=") || !path.contains("permlink=")) { + path = "/watch?owner=sagarkothari88&permlink=gqbffyah"; + } + var comps = path + .replaceAll("?", "&") + .split("&") + .where((element) => + element.contains('owner=') || element.contains('permlink=')) + .toList(); + if (comps.length < 2) { + comps = "/watch?owner=sagarkothari88&permlink=gqbffyah" + .replaceAll("?", "&") + .split("&") + .where((element) => + element.contains('owner=') || element.contains('permlink=')) + .toList(); + } + comps.sort(); + var firstComp = comps[0].split("="); + if (firstComp.length < 2) { + firstComp[1] = "sagarkothari88"; } + var secondComp = comps[1].split("="); + if (secondComp.length < 2) { + secondComp[1] = "gqbffyah"; + } + var author = firstComp[1]; + var permlink = secondComp[1]; + return VideoDetailsViewModel( + path: path, author: author, permlink: permlink); } + } diff --git a/lib/src/screens/video_details_screen/video_details_widgets.dart b/lib/src/screens/video_details_screen/video_details_widgets.dart deleted file mode 100644 index a714b7d0..00000000 --- a/lib/src/screens/video_details_screen/video_details_widgets.dart +++ /dev/null @@ -1,184 +0,0 @@ -import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; -import 'package:acela/src/widgets/controls_overlay.dart'; -import 'package:acela/src/widgets/custom_circle_avatar.dart'; -import 'package:acela/src/widgets/loading_screen.dart'; -import 'package:acela/src/widgets/retry.dart'; -import 'package:flutter/material.dart'; -import 'package:timeago/timeago.dart' as timeago; -import 'package:flutter_markdown/flutter_markdown.dart'; -import 'package:video_player/video_player.dart'; - -class VideoDetailsScreenWidgets { - var showAppBar = true; - static const List tabs = [ - Tab(text: 'Video'), - Tab(text: 'Description'), - Tab(text: 'Comments') - ]; - - Widget tabBar( - BuildContext context, - Widget videoView, - VideoDetailsViewModel vm, - Function stateUpdated, - ) { - return DefaultTabController( - length: tabs.length, - child: Builder( - builder: (context) { - return Scaffold( - appBar: showAppBar - ? AppBar( - title: Text(vm.item.title), - bottom: const TabBar(tabs: tabs), - ) - : null, - body: TabBarView( - children: [ - videoView, - getDescription(context, vm, stateUpdated), - getComments(context, vm, stateUpdated) - ], - ), - floatingActionButton: FloatingActionButton( - child: showAppBar - ? const Icon(Icons.fullscreen) - : const Icon(Icons.fullscreen_exit), - onPressed: () { - showAppBar = !showAppBar; - stateUpdated(); - }, - ), - ); - }, - ), - ); - } - - Widget descriptionMarkDown(String markDown) { - return Container( - margin: const EdgeInsets.all(10), - child: Markdown( - data: markDown, - ), - ); - } - - Widget getDescription( - BuildContext context, VideoDetailsViewModel vm, Function stateUpdated) { - return vm.descState == LoadState.loading - ? const LoadingScreen() - : vm.descState == LoadState.failed - ? RetryScreen( - error: vm.descError, - onRetry: () { - vm.descState = LoadState.notStarted; - vm.loadVideoInfo(stateUpdated); - }) - : descriptionMarkDown(vm.description!.description); - } - - Widget commentsListView(VideoDetailsViewModel vm) { - return ListView.separated( - itemBuilder: (context, index) { - var item = vm.comments[index]; - var userThumb = server.userOwnerThumb(item.author); - var author = item.author; - var body = item.body; - var upVotes = item.activeVotes.where((e) => e.percent > 0).length; - var downVotes = item.activeVotes.where((e) => e.percent < 0).length; - var payout = item.pendingPayoutValue.replaceAll(" HBD", ""); - var timeInString = item.createdAt != null - ? "📆 ${timeago.format(item.createdAt!)}" - : ""; - var text = - "👤 $author 👍 $upVotes 👎 $downVotes 💰 $payout $timeInString"; - var depth = (item.depth * 25.0) - 25; - double width = MediaQuery.of(context).size.width - 70 - depth; - - return ListTile( - title: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container(margin: EdgeInsets.only(left: depth)), - CustomCircleAvatar(height: 25, width: 25, url: userThumb), - Container(margin: const EdgeInsets.only(right: 10)), - SizedBox( - width: width, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - MarkdownBody( - data: body, - shrinkWrap: true, - ), - Container(margin: const EdgeInsets.only(bottom: 10)), - Text( - text, - style: Theme.of(context).textTheme.bodyText1, - ), - ], - ), - ) - ], - ), - onTap: () { - print("Tapped"); - }, - ); - }, - separatorBuilder: (context, index) => const Divider( - height: 10, - color: Colors.blueGrey, - ), - itemCount: vm.comments.length); - } - - Widget getComments( - BuildContext context, VideoDetailsViewModel vm, Function stateUpdated) { - return vm.commentsState == LoadState.loading - ? const LoadingScreen() - : vm.commentsState == LoadState.failed - ? RetryScreen( - error: vm.commentsError, - onRetry: () { - vm.commentsState = LoadState.notStarted; - vm.loadComments( - vm.item.author, vm.item.permlink, stateUpdated); - }) - : commentsListView(vm); - } - - Widget getPlayer(BuildContext context, VideoPlayerController controller) { - return Center( - child: controller.value.isInitialized - ? AspectRatio( - aspectRatio: controller.value.aspectRatio, - child: Stack( - alignment: Alignment.bottomCenter, - children: [ - VideoPlayer(controller), - ClosedCaption(text: controller.value.caption.text), - ControlsOverlay(controller: controller), - VideoProgressIndicator(controller, allowScrubbing: true), - ], - ), - ) - : Container(), - ); - } - - FloatingActionButton getFab( - VideoPlayerController? _controller, Function() onPressed) { - return FloatingActionButton( - onPressed: () { - onPressed(); - }, - child: Icon( - _controller?.value.isPlaying ?? false ? Icons.pause : Icons.play_arrow, - ), - ); - } -} diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart new file mode 100644 index 00000000..f4f4e15d --- /dev/null +++ b/lib/src/widgets/video_player.dart @@ -0,0 +1,53 @@ +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:video_player/video_player.dart'; +import 'package:acela/src/widgets/controls_overlay.dart'; + +class SPKVideoPlayer extends StatefulWidget { + const SPKVideoPlayer({Key? key, required this.playUrl}) : super(key: key); + final String playUrl; + + @override + _SPKVideoPlayerState createState() => _SPKVideoPlayerState(); +} + +class _SPKVideoPlayerState extends State { + late VideoPlayerController controller; + + @override + void dispose() { + super.dispose(); + controller.dispose(); + } + + @override + void initState() { + controller = VideoPlayerController.network(widget.playUrl) + ..initialize().then((_) { + setState(() { + controller.play(); + }); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Center( + child: controller.value.isInitialized + ? AspectRatio( + aspectRatio: controller.value.aspectRatio, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + VideoPlayer(controller), + ClosedCaption(text: controller.value.caption.text), + ControlsOverlay(controller: controller), + VideoProgressIndicator(controller, allowScrubbing: true), + ], + ), + ) + : const LoadingScreen(), + ); + } +} From ddb1ae4e9708e13bc23cdd87caf00996de4b0aaa Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 10 Feb 2022 01:11:51 +0530 Subject: [PATCH 013/466] keeping state alive for video player & comments section. --- .flutter-plugins-dependencies | 2 +- .../video_details_comments.dart | 7 ++- .../video_details_tabbed_widget.dart | 50 +++++++++++++++++++ lib/src/widgets/video_player.dart | 4 +- 4 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 lib/src/screens/video_details_screen/video_details_tabbed_widget.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index c6c8af1b..eca19f8e 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-10 00:38:24.036116","version":"2.10.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-10 01:08:24.077942","version":"2.10.0"} \ No newline at end of file diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart index 0da454eb..7f4ee792 100644 --- a/lib/src/screens/video_details_screen/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -20,8 +20,11 @@ class VideoDetailsCommentsWidget extends StatefulWidget { _VideoDetailsCommentsWidgetState(); } -class _VideoDetailsCommentsWidgetState - extends State { +class _VideoDetailsCommentsWidgetState extends State + with AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + Future> loadComments(String author, String permlink) async { var client = http.Client(); var body = diff --git a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart new file mode 100644 index 00000000..2d03ad23 --- /dev/null +++ b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +class VideoDetailsTabbedWidget extends StatefulWidget { + const VideoDetailsTabbedWidget({Key? key, required this.children}) + : super(key: key); + final List children; + + @override + _VideoDetailsTabbedWidgetState createState() => + _VideoDetailsTabbedWidgetState(); +} + +class _VideoDetailsTabbedWidgetState extends State + with SingleTickerProviderStateMixin { + static const List tabs = [ + Tab(text: 'Video'), + Tab(text: 'Description'), + Tab(text: 'Comments') + ]; + + late TabController _tabController; + + @override + void initState() { + super.initState(); + _tabController = TabController(vsync: this, length: tabs.length); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + bottom: TabBar( + controller: _tabController, + tabs: tabs, + ), + ), + body: TabBarView( + controller: _tabController, + children: widget.children, + ), + ); + } +} diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index f4f4e15d..96bfa799 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -11,8 +11,10 @@ class SPKVideoPlayer extends StatefulWidget { _SPKVideoPlayerState createState() => _SPKVideoPlayerState(); } -class _SPKVideoPlayerState extends State { +class _SPKVideoPlayerState extends State with AutomaticKeepAliveClientMixin { late VideoPlayerController controller; + @override + bool get wantKeepAlive => true; @override void dispose() { From 19bfdecdf7da2794859688a03922a2f8ae6a617a Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 10 Feb 2022 11:06:16 +0530 Subject: [PATCH 014/466] Lot of code refactoring. --- .flutter-plugins-dependencies | 2 +- lib/src/screens/home_screen/home_screen.dart | 32 ++++++---- .../home_screen/home_screen_view_model.dart | 27 ++------ .../video_details_comments.dart | 56 +++++------------ .../video_details_screen.dart | 63 ++++++------------- .../video_details_tabbed_widget.dart | 5 +- .../video_details_view_model.dart | 49 +++++++++++---- 7 files changed, 101 insertions(+), 133 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index eca19f8e..f090019b 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-10 01:08:24.077942","version":"2.10.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-10 10:47:28.689690","version":"2.10.0"} \ No newline at end of file diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 1f4fdaf7..66b4aa46 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -28,29 +28,35 @@ class HomeScreen extends StatefulWidget { class _HomeScreenState extends State { final widgets = HomeScreenWidgets(); late HomeScreenViewModel vm; + late Future> _loadingFeed; @override void initState() { super.initState(); - vm = HomeScreenViewModel( - path: widget.path, - stateUpdated: () { - setState(() {}); - }); - vm.loadHomeFeed(); + vm = HomeScreenViewModel(path: widget.path); + _loadingFeed = vm.loadHomeFeed(); } void onTap(HomeFeedItem item) { - Navigator.of(context).pushNamed( - VideoDetailsScreen.routeName(item.author, item.permlink)); + Navigator.of(context) + .pushNamed(VideoDetailsScreen.routeName(item.author, item.permlink)); } Widget _screen() { - return vm.state == LoadState.loading - ? widgets.loadingData() - : vm.state == LoadState.failed - ? RetryScreen(error: vm.error, onRetry: vm.loadHomeFeed) - : widgets.list(vm.list, vm.loadHomeFeed, onTap); + return FutureBuilder( + future: _loadingFeed, + builder: (builder, snapshot) { + if (snapshot.hasError) { + return RetryScreen( + error: snapshot.error?.toString() ?? 'Something went wrong', + onRetry: vm.loadHomeFeed); + } else if (snapshot.hasData) { + List items = snapshot.data! as List; + return widgets.list(items, vm.loadHomeFeed, onTap); + } else { + return widgets.loadingData(); + } + }); } @override diff --git a/lib/src/screens/home_screen/home_screen_view_model.dart b/lib/src/screens/home_screen/home_screen_view_model.dart index dce47cbf..ceeb4666 100644 --- a/lib/src/screens/home_screen/home_screen_view_model.dart +++ b/lib/src/screens/home_screen/home_screen_view_model.dart @@ -1,36 +1,17 @@ import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:http/http.dart' show get; -enum LoadState { - notStarted, - loading, - succeeded, - failed, -} - class HomeScreenViewModel { - LoadState state = LoadState.notStarted; - List list = []; - String error = 'Something went wrong'; - Function() stateUpdated; - - HomeScreenViewModel({required this.path, required this.stateUpdated}); + HomeScreenViewModel({required this.path}); final String path; - Future loadHomeFeed() async { - state = LoadState.loading; - stateUpdated(); + Future> loadHomeFeed() async { var response = await get(Uri.parse(path)); if (response.statusCode == 200) { List list = homeFeedItemFromString(response.body); - state = LoadState.succeeded; - this.list = list; - stateUpdated(); + return list; } else { - error = - 'Something went wrong.\nStatus code is ${response.statusCode} for $path'; - state = LoadState.failed; - stateUpdated(); + throw 'Status code ${response.statusCode}'; } } } \ No newline at end of file diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart index 7f4ee792..395efa83 100644 --- a/lib/src/screens/video_details_screen/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -1,19 +1,17 @@ import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; -import 'package:http/http.dart' as http; import 'package:timeago/timeago.dart' as timeago; class VideoDetailsCommentsWidget extends StatefulWidget { const VideoDetailsCommentsWidget( - {Key? key, required this.author, required this.permlink}) + {Key? key, required this.vm}) : super(key: key); - final String author; - final String permlink; + final VideoDetailsViewModel vm; @override _VideoDetailsCommentsWidgetState createState() => @@ -25,31 +23,6 @@ class _VideoDetailsCommentsWidgetState extends State @override bool get wantKeepAlive => true; - Future> loadComments(String author, String permlink) async { - var client = http.Client(); - var body = - hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); - var response = await client.post(Uri.parse(server.hiveDomain), body: body); - if (response.statusCode == 200) { - var hiveCommentsResponse = hiveCommentsFromString(response.body); - var comments = hiveCommentsResponse.result; - for (var i = 0; i < comments.length; i++) { - if (comments[i].children > 0) { - if (comments - .where((e) => e.parentPermlink == comments[i].permlink) - .isEmpty) { - var newComments = - await loadComments(comments[i].author, comments[i].permlink); - comments.insertAll(i + 1, newComments); - } - } - } - return comments; - } else { - throw "Status code is ${response.statusCode}"; - } - } - Widget listTile(HiveComment comment) { var item = comment; var userThumb = server.userOwnerThumb(item.author); @@ -97,21 +70,24 @@ class _VideoDetailsCommentsWidgetState extends State } Widget commentsListView(List comments) { - return ListView.separated( - itemBuilder: (context, index) { - return listTile(comments[index]); - }, - separatorBuilder: (context, index) => const Divider( - height: 10, - color: Colors.blueGrey, - ), - itemCount: comments.length); + return Container( + margin: const EdgeInsets.only(top: 10, bottom: 10), + child: ListView.separated( + itemBuilder: (context, index) { + return listTile(comments[index]); + }, + separatorBuilder: (context, index) => const Divider( + height: 10, + color: Colors.blueGrey, + ), + itemCount: comments.length), + ); } @override Widget build(BuildContext context) { return FutureBuilder( - future: loadComments(widget.author, widget.permlink), + future: widget.vm.loadComments(widget.vm.author, widget.vm.permlink), builder: (builder, snapshot) { if (snapshot.hasError) { String text = diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index dff75903..f88802e4 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -1,6 +1,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_tabbed_widget.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/video_player.dart'; @@ -21,24 +22,6 @@ class VideoDetailsScreen extends StatefulWidget { } class _VideoDetailsScreenState extends State { - static const List tabs = [ - Tab(text: 'Video'), - Tab(text: 'Description'), - Tab(text: 'Comments') - ]; - - Future getVideoDetails() async { - final endPoint = - "${server.domain}/apiv2/@${widget.vm.author}/${widget.vm.permlink}"; - var response = await get(Uri.parse(endPoint)); - if (response.statusCode == 200) { - VideoDetails data = videoDetailsFromJson(response.body); - return data; - } else { - throw "Status code = ${response.statusCode}"; - } - } - Widget container(String title, Widget body) { return Scaffold( appBar: AppBar( @@ -57,44 +40,36 @@ class _VideoDetailsScreenState extends State { ); } - Widget tabBar(VideoDetails details) { - return DefaultTabController( - length: tabs.length, - child: Builder( - builder: (context) { - return Scaffold( - appBar: AppBar( - title: Text(details.title), - bottom: const TabBar(tabs: tabs), - ), - body: TabBarView( - children: [ - SPKVideoPlayer( - playUrl: details.playUrl, - ), - descriptionMarkDown(details.description), - VideoDetailsCommentsWidget( - author: details.owner, permlink: details.permlink), - ], - ), - ); - }, + List tabBarChildren(VideoDetails details) { + return [ + SPKVideoPlayer( + playUrl: details.playUrl, ), - ); + descriptionMarkDown(details.description), + VideoDetailsCommentsWidget(vm: widget.vm), + ]; } @override Widget build(BuildContext context) { return FutureBuilder( - future: getVideoDetails(), + future: widget.vm.getVideoDetails(), builder: (builder, snapshot) { if (snapshot.hasError) { String text = 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; return container(widget.vm.author, Text(text)); } else if (snapshot.hasData) { - var data = snapshot.data! as VideoDetails; - return tabBar(data); + var data = snapshot.data as VideoDetails?; + if (data != null) { + return VideoDetailsTabbedWidget( + children: tabBarChildren(data), + title: data.title, + ); + } else { + return container( + widget.vm.author, const Text("Something went wrong")); + } } else { return container(widget.vm.author, const LoadingScreen()); } diff --git a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart index 2d03ad23..8cb7f2fc 100644 --- a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart +++ b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart @@ -1,9 +1,11 @@ import 'package:flutter/material.dart'; class VideoDetailsTabbedWidget extends StatefulWidget { - const VideoDetailsTabbedWidget({Key? key, required this.children}) + const VideoDetailsTabbedWidget( + {Key? key, required this.children, required this.title}) : super(key: key); final List children; + final String title; @override _VideoDetailsTabbedWidgetState createState() => @@ -36,6 +38,7 @@ class _VideoDetailsTabbedWidgetState extends State Widget build(BuildContext context) { return Scaffold( appBar: AppBar( + title: Text(widget.title), bottom: TabBar( controller: _tabController, tabs: tabs, diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index 383f3061..cf5bd459 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -1,27 +1,18 @@ +import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; +import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_details_model/video_details_description.dart'; import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; import 'package:http/http.dart' show get; import 'package:http/http.dart' as http; -import 'package:acela/src/bloc/server.dart'; class VideoDetailsViewModel { - // loading info - LoadState descState = LoadState.notStarted; - String descError = 'Something went wrong'; - VideoDetailsDescription? description; - // view String path; String author; String permlink; - // loading comments - LoadState commentsState = LoadState.notStarted; - String commentsError = 'Something went wrong'; - List comments = []; - VideoDetailsViewModel( {required this.path, required this.author, required this.permlink}); @@ -58,4 +49,40 @@ class VideoDetailsViewModel { path: path, author: author, permlink: permlink); } + Future getVideoDetails() async { + final endPoint = + "${server.domain}/apiv2/@$author/$permlink"; + var response = await get(Uri.parse(endPoint)); + if (response.statusCode == 200) { + VideoDetails data = videoDetailsFromJson(response.body); + return data; + } else { + throw "Status code = ${response.statusCode}"; + } + } + + Future> loadComments(String author, String permlink) async { + var client = http.Client(); + var body = + hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); + var response = await client.post(Uri.parse(server.hiveDomain), body: body); + if (response.statusCode == 200) { + var hiveCommentsResponse = hiveCommentsFromString(response.body); + var comments = hiveCommentsResponse.result; + for (var i = 0; i < comments.length; i++) { + if (comments[i].children > 0) { + if (comments + .where((e) => e.parentPermlink == comments[i].permlink) + .isEmpty) { + var newComments = + await loadComments(comments[i].author, comments[i].permlink); + comments.insertAll(i + 1, newComments); + } + } + } + return comments; + } else { + throw "Status code is ${response.statusCode}"; + } + } } From 4e5bae5524443bc3c5856537666976c4c47b732e Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 10 Feb 2022 21:36:19 +0530 Subject: [PATCH 015/466] Integrated first uploads. --- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 4 +- .packages | 4 +- lib/main.dart | 62 ++++++++----------- .../screens/drawer_screen/drawer_screen.dart | 9 ++- pubspec.lock | 2 +- 6 files changed, 37 insertions(+), 46 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index f090019b..0aae7186 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-10 10:47:28.689690","version":"2.10.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-10 21:07:52.756282","version":"2.10.0"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index d07c8e25..ed93ca50 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -509,7 +509,7 @@ - @@ -668,7 +668,7 @@ - + diff --git a/.packages b/.packages index 89e1dc7a..484639d4 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-02-08 01:27:05.202770. +# Generated by pub on 2022-02-10 11:13:38.680297. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-34.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.2.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ @@ -76,7 +76,7 @@ stream_transform:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dart string_scanner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib/ term_glyph:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0/lib/ test_api:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.8/lib/ -timeago:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timeago-3.2.1/lib/ +timeago:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timeago-3.2.2/lib/ timing:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timing-1.0.0/lib/ typed_data:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib/ vector_math:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.1/lib/ diff --git a/lib/main.dart b/lib/main.dart index 4fec279d..b1450b28 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -39,6 +39,22 @@ class _MyAppState extends State { }); } + MaterialPageRoute configuredHomeWidget(String title, String path, bool showDrawer) { + return MaterialPageRoute(builder: (context) { + return HomeScreen( + path: path, //"${server.domain}/apiv2/feeds/home", + showDrawer: showDrawer, + title: title, + isDarkMode: isDarkMode, + switchDarkMode: () { + setState(() { + isDarkMode = !isDarkMode; + }); + }, + ); + }); + } + // This widget is the root of your application. @override Widget build(BuildContext context) { @@ -53,45 +69,17 @@ class _MyAppState extends State { vm: VideoDetailsViewModel.from(settings.name!)); }); } else if (settings.name == "/") { - return MaterialPageRoute(builder: (context) { - return HomeScreen( - path: "${server.domain}/apiv2/feeds/home", - showDrawer: true, - title: 'Home', - isDarkMode: isDarkMode, - switchDarkMode: () { - setState(() { - isDarkMode = !isDarkMode; - }); - }, - ); - }); + return configuredHomeWidget( + 'Home', "${server.domain}/apiv2/feeds/home", true); } else if (settings.name == "/trending") { - return MaterialPageRoute(builder: (context) { - return HomeScreen( - path: "${server.domain}/apiv2/feeds/trending", - showDrawer: false, - title: 'Trending Content', - isDarkMode: isDarkMode, - switchDarkMode: () { - setState(() { - isDarkMode = !isDarkMode; - }); - }); - }); + return configuredHomeWidget( + 'Trending Content', "${server.domain}/apiv2/feeds/trending", false); } else if (settings.name == "/new") { - return MaterialPageRoute(builder: (context) { - return HomeScreen( - path: "${server.domain}/apiv2/feeds/new", - showDrawer: false, - title: 'New Content', - isDarkMode: isDarkMode, - switchDarkMode: () { - setState(() { - isDarkMode = !isDarkMode; - }); - }); - }); + return configuredHomeWidget( + 'New Content', "${server.domain}/apiv2/feeds/new", false); + } else if (settings.name == "/firstUploads") { + return configuredHomeWidget( + 'First Uploads', "${server.domain}/apiv2/feeds/firstUploads", false); } else if (settings.name == "/leaderboard") { return MaterialPageRoute(builder: (context) { return const LeaderboardScreen(); diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 058c2938..52f89901 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -18,11 +18,14 @@ class DrawerScreen extends StatelessWidget { ); } - Widget _firstUploads() { + Widget _firstUploads(BuildContext context) { return ListTile( leading: const Icon(Icons.emoji_emotions_outlined), title: const Text("First Uploads"), - onTap: () {}, + onTap: () { + Navigator.pop(context); + Navigator.of(context).pushNamed("/firstUploads"); + }, ); } @@ -112,7 +115,7 @@ class DrawerScreen extends StatelessWidget { height: 1, color: Colors.blueGrey, ), - _firstUploads(), + _firstUploads(context), const Divider( height: 1, color: Colors.blueGrey, diff --git a/pubspec.lock b/pubspec.lock index 67934e25..0bcb90fb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -503,7 +503,7 @@ packages: name: timeago url: "https://pub.dartlang.org" source: hosted - version: "3.2.1" + version: "3.2.2" timing: dependency: transitive description: From d9c2d96093f090ee69ebad41d7c310da85fd8ad7 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 10 Feb 2022 21:37:45 +0530 Subject: [PATCH 016/466] there is no need of home menu. --- lib/src/screens/drawer_screen/drawer_screen.dart | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 52f89901..9b9924a2 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -8,16 +8,6 @@ class DrawerScreen extends StatelessWidget { final bool isDarkMode; final Function switchDarkMode; - Widget _homeMenu(BuildContext context) { - return ListTile( - leading: const Icon(Icons.home), - title: const Text("Home"), - onTap: () { - Navigator.pop(context); - }, - ); - } - Widget _firstUploads(BuildContext context) { return ListTile( leading: const Icon(Icons.emoji_emotions_outlined), @@ -110,7 +100,6 @@ class DrawerScreen extends StatelessWidget { return ListView( children: [ _drawerHeader(context), - _homeMenu(context), const Divider( height: 1, color: Colors.blueGrey, From 03ce9e7661fc8b0069a5e2b2c896e24e238cfdd4 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 10 Feb 2022 21:40:55 +0530 Subject: [PATCH 017/466] removed unwanted separator --- lib/src/screens/drawer_screen/drawer_screen.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 9b9924a2..b2afaafd 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -100,10 +100,6 @@ class DrawerScreen extends StatelessWidget { return ListView( children: [ _drawerHeader(context), - const Divider( - height: 1, - color: Colors.blueGrey, - ), _firstUploads(context), const Divider( height: 1, From ebdf8d8e0742d810602116d058d2a2c4d3e93a67 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 11 Feb 2022 09:49:38 +0530 Subject: [PATCH 018/466] User channel works now. --- .flutter-plugins-dependencies | 2 +- lib/main.dart | 4 ++ lib/src/bloc/server.dart | 5 +++ .../screens/drawer_screen/drawer_screen.dart | 37 +++++++------------ lib/src/screens/home_screen/home_screen.dart | 6 ++- .../home_screen/home_screen_widgets.dart | 19 ++++++---- lib/src/widgets/list_tile_video.dart | 12 +++++- 7 files changed, 50 insertions(+), 35 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 0aae7186..cc187d3a 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-10 21:07:52.756282","version":"2.10.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-11 09:47:13.637422","version":"2.10.0"} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index b1450b28..254bf169 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -80,6 +80,10 @@ class _MyAppState extends State { } else if (settings.name == "/firstUploads") { return configuredHomeWidget( 'First Uploads', "${server.domain}/apiv2/feeds/firstUploads", false); + } else if (settings.name?.contains("/userChannel/") == true) { + var last = settings.name?.split("/userChannel/").last ?? "sagarkothari88"; + return configuredHomeWidget( + last, "${server.domain}/apiv2/feeds/@$last", false); } else if (settings.name == "/leaderboard") { return MaterialPageRoute(builder: (context) { return const LeaderboardScreen(); diff --git a/lib/src/bloc/server.dart b/lib/src/bloc/server.dart index a238440c..5da5fdf8 100644 --- a/lib/src/bloc/server.dart +++ b/lib/src/bloc/server.dart @@ -2,10 +2,15 @@ import 'dart:developer'; class Server { final String domain = "https://3speak.tv"; + String userOwnerThumb(String value) { return "https://images.hive.blog/u/$value/avatar"; } + String userChannelCover(String value) { + return "https://img.3speakcontent.co/user/$value/cover.png"; + } + String resizedImage(String value) { return "https://images.hive.blog/320x160/$value"; } diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index b2afaafd..ab6d729b 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -96,40 +96,29 @@ class DrawerScreen extends StatelessWidget { ); } + Widget _divider() { + return const Divider( + height: 1, + color: Colors.blueGrey, + ); + } + Widget _drawerMenu(BuildContext context) { return ListView( children: [ _drawerHeader(context), _firstUploads(context), - const Divider( - height: 1, - color: Colors.blueGrey, - ), + _divider(), _trendingContent(context), - const Divider( - height: 1, - color: Colors.blueGrey, - ), + _divider(), _newContent(context), - const Divider( - height: 1, - color: Colors.blueGrey, - ), + _divider(), _communities(), - const Divider( - height: 1, - color: Colors.blueGrey, - ), + _divider(), _leaderBoard(context), - const Divider( - height: 1, - color: Colors.blueGrey, - ), + _divider(), _changeTheme(), - const Divider( - height: 1, - color: Colors.blueGrey, - ), + _divider(), ], ); } diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 66b4aa46..53837232 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -42,6 +42,10 @@ class _HomeScreenState extends State { .pushNamed(VideoDetailsScreen.routeName(item.author, item.permlink)); } + void onUserTap(HomeFeedItem item) { + Navigator.of(context).pushNamed("/userChannel/${item.author}"); + } + Widget _screen() { return FutureBuilder( future: _loadingFeed, @@ -52,7 +56,7 @@ class _HomeScreenState extends State { onRetry: vm.loadHomeFeed); } else if (snapshot.hasData) { List items = snapshot.data! as List; - return widgets.list(items, vm.loadHomeFeed, onTap); + return widgets.list(items, vm.loadHomeFeed, onTap, onUserTap); } else { return widgets.loadingData(); } diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index feb7962a..00a4993f 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -11,8 +11,10 @@ class HomeScreenWidgets { return const LoadingScreen(); } - Widget _tileTitle(HomeFeedItem item, BuildContext context) { - String timeInString = item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; + Widget _tileTitle(HomeFeedItem item, BuildContext context, + Function(HomeFeedItem) onUserTap) { + String timeInString = + item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; String owner = "👤 ${item.author}"; String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; String views = "▶ ${item.views}"; @@ -22,13 +24,16 @@ class HomeScreenWidgets { userThumbUrl: server.userOwnerThumb(item.author), title: item.title, subtitle: "$timeInString $owner $duration $views", + onUserTap: () { + onUserTap(item); + }, ); } - Widget _listTile( - HomeFeedItem item, BuildContext context, Function(HomeFeedItem) onTap) { + Widget _listTile(HomeFeedItem item, BuildContext context, + Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { return ListTile( - title: _tileTitle(item, context), + title: _tileTitle(item, context, onUserTap), onTap: () { onTap(item); }, @@ -36,7 +41,7 @@ class HomeScreenWidgets { } Widget list(List list, Future Function() onRefresh, - Function(HomeFeedItem) onTap) { + Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { return Container( padding: const EdgeInsets.only(top: 10, bottom: 10), child: RefreshIndicator( @@ -44,7 +49,7 @@ class HomeScreenWidgets { child: ListView.separated( physics: const AlwaysScrollableScrollPhysics(), itemBuilder: (context, index) { - return _listTile(list[index], context, onTap); + return _listTile(list[index], context, onTap, onUserTap); }, separatorBuilder: (context, index) => const Divider( thickness: 0, diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index 8a14b962..65441fea 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -11,7 +11,8 @@ class ListTileVideo extends StatelessWidget { required this.url, required this.userThumbUrl, required this.title, - required this.subtitle}) + required this.subtitle, + required this.onUserTap}) : super(key: key); final String placeholder; @@ -19,6 +20,7 @@ class ListTileVideo extends StatelessWidget { final String userThumbUrl; final String title; final String subtitle; + final Function onUserTap; Widget _commonContainer(BuildContext context, Widget child) { return Container( @@ -68,7 +70,13 @@ class ListTileVideo extends StatelessWidget { padding: const EdgeInsets.all(10), child: Row( children: [ - CustomCircleAvatar(height: 40, width: 40, url: userThumbUrl), + GestureDetector( + child: CustomCircleAvatar( + height: 40, width: 40, url: userThumbUrl), + onTap: () { + onUserTap(); + }, + ), Container(width: 5), Flexible( child: Column( From 34f5dd846a7bde463b49554e3614fed1f37457a6 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 11 Feb 2022 10:57:51 +0530 Subject: [PATCH 019/466] On Video Details page, I've added a button on top-right to navigate to user channel. --- .flutter-plugins-dependencies | 2 +- .../video_details_screen/video_details_screen.dart | 8 ++++++++ .../video_details_tabbed_widget.dart | 13 ++++++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index cc187d3a..89ab9633 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-11 09:47:13.637422","version":"2.10.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-11 10:54:17.580737","version":"2.10.0"} \ No newline at end of file diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index f88802e4..3ef9e914 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -22,10 +22,17 @@ class VideoDetailsScreen extends StatefulWidget { } class _VideoDetailsScreenState extends State { + void onUserTap() { + Navigator.of(context).pushNamed("/userChannel/${widget.vm.author}"); + } + Widget container(String title, Widget body) { return Scaffold( appBar: AppBar( title: Text(title), + actions: [ + IconButton(onPressed: onUserTap, icon: const Icon(Icons.person)), + ], ), body: body, ); @@ -65,6 +72,7 @@ class _VideoDetailsScreenState extends State { return VideoDetailsTabbedWidget( children: tabBarChildren(data), title: data.title, + onUserTap: onUserTap, ); } else { return container( diff --git a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart index 8cb7f2fc..65d12afe 100644 --- a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart +++ b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart @@ -2,10 +2,14 @@ import 'package:flutter/material.dart'; class VideoDetailsTabbedWidget extends StatefulWidget { const VideoDetailsTabbedWidget( - {Key? key, required this.children, required this.title}) + {Key? key, + required this.children, + required this.title, + required this.onUserTap}) : super(key: key); final List children; final String title; + final Function onUserTap; @override _VideoDetailsTabbedWidgetState createState() => @@ -39,6 +43,13 @@ class _VideoDetailsTabbedWidgetState extends State return Scaffold( appBar: AppBar( title: Text(widget.title), + actions: [ + IconButton( + onPressed: () { + widget.onUserTap(); + }, + icon: const Icon(Icons.person)), + ], bottom: TabBar( controller: _tabController, tabs: tabs, From 2e99c08f614c55d1d20b6cd77e8e60d76518e41d Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 11 Feb 2022 11:34:35 +0530 Subject: [PATCH 020/466] communities - work in progress. --- .flutter-plugins-dependencies | 2 +- lib/main.dart | 5 + lib/src/bloc/server.dart | 4 + .../request/communities_request_model.dart | 58 ++++++++++++ .../response/communities_response_models.dart | 89 ++++++++++++++++++ .../communities_screen.dart | 94 +++++++++++++++++++ .../screens/drawer_screen/drawer_screen.dart | 9 +- .../video_details_view_model.dart | 2 - 8 files changed, 257 insertions(+), 6 deletions(-) create mode 100644 lib/src/models/communities_models/request/communities_request_model.dart create mode 100644 lib/src/models/communities_models/response/communities_response_models.dart create mode 100644 lib/src/screens/communities_screen/communities_screen.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 89ab9633..e46b4670 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-11 10:54:17.580737","version":"2.10.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-11 11:33:42.909732","version":"2.10.0"} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 254bf169..b5ed1731 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:acela/src/screens/communities_screen/communities_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; @@ -88,6 +89,10 @@ class _MyAppState extends State { return MaterialPageRoute(builder: (context) { return const LeaderboardScreen(); }); + } else if (settings.name == "/communities") { + return MaterialPageRoute(builder: (context) { + return const CommunitiesScreen(); + }); } assert(false, 'Need to implement ${settings.name}'); return null; diff --git a/lib/src/bloc/server.dart b/lib/src/bloc/server.dart index 5da5fdf8..69981ddc 100644 --- a/lib/src/bloc/server.dart +++ b/lib/src/bloc/server.dart @@ -11,6 +11,10 @@ class Server { return "https://img.3speakcontent.co/user/$value/cover.png"; } + String communityIcon(String value) { + return "https://images.hive.blog/u/$value/avatar?size=icon"; + } + String resizedImage(String value) { return "https://images.hive.blog/320x160/$value"; } diff --git a/lib/src/models/communities_models/request/communities_request_model.dart b/lib/src/models/communities_models/request/communities_request_model.dart new file mode 100644 index 00000000..c3252c98 --- /dev/null +++ b/lib/src/models/communities_models/request/communities_request_model.dart @@ -0,0 +1,58 @@ +import 'package:acela/src/utils/safe_convert.dart'; +import 'dart:convert'; + +String communitiesRequestModelToJson(CommunitiesRequestModel data) => + json.encode(data.toJson()); + +class CommunitiesRequestModel { + final CommunitiesRequestParams params; + + // 2.0 + final String jsonrpc; + + // bridge.list_communities + final String method; + + // 1 + final int id; + + CommunitiesRequestModel({ + required this.params, + this.jsonrpc = "2.0", + this.method = "bridge.list_communities", + this.id = 1, + }); + + factory CommunitiesRequestModel.fromJson(Map? json) => + CommunitiesRequestModel( + params: CommunitiesRequestParams.fromJson(asMap(json, 'params')), + jsonrpc: asString(json, 'jsonrpc'), + method: asString(json, 'method'), + id: asInt(json, 'id'), + ); + + Map toJson() => { + 'params': params.toJson(), + 'jsonrpc': jsonrpc, + 'method': method, + 'id': id, + }; +} + +class CommunitiesRequestParams { + // 100 + final int limit; + + CommunitiesRequestParams({ + this.limit = 100, + }); + + factory CommunitiesRequestParams.fromJson(Map? json) => + CommunitiesRequestParams( + limit: asInt(json, 'limit'), + ); + + Map toJson() => { + 'limit': limit, + }; +} diff --git a/lib/src/models/communities_models/response/communities_response_models.dart b/lib/src/models/communities_models/response/communities_response_models.dart new file mode 100644 index 00000000..cea00d48 --- /dev/null +++ b/lib/src/models/communities_models/response/communities_response_models.dart @@ -0,0 +1,89 @@ +import 'package:acela/src/utils/safe_convert.dart'; +import 'dart:convert'; + +CommunitiesResponseModel communitiesResponseModelFromString(String string) { + return CommunitiesResponseModel.fromJson(json.decode(string)); +} + +class CommunitiesResponseModel { + // 2.0 + final String jsonrpc; + final List result; + // 1 + final int id; + + CommunitiesResponseModel({ + this.jsonrpc = "", + required this.result, + this.id = 0, + }); + + factory CommunitiesResponseModel.fromJson(Map? json) => CommunitiesResponseModel( + jsonrpc: asString(json, 'jsonrpc'), + result: asList(json, 'result').map((e) => CommunityItem.fromJson(e)).toList(), + id: asInt(json, 'id'), + ); + + Map toJson() => { + 'jsonrpc': jsonrpc, + 'result': result.map((e) => e.toJson()), + 'id': id, + }; +} + +class CommunityItem { + // 1341662 + final int id; + // hive-167922 + final String name; + // LeoFinance + final String title; + // LeoFinance is a community for crypto & finance. Powered by Hive and the LEO token economy. + final String about; + // 1 + final int typeId; + // false + final bool isNsfw; + // 11475 + final int subscribers; + // 29860 + final int sumPending; + final List admins; + + CommunityItem({ + this.id = 0, + this.name = "", + this.title = "", + this.about = "", + this.typeId = 0, + this.isNsfw = false, + this.subscribers = 0, + this.sumPending = 0, + required this.admins, + }); + + factory CommunityItem.fromJson(Map? json) => CommunityItem( + id: asInt(json, 'id'), + name: asString(json, 'name'), + title: asString(json, 'title'), + about: asString(json, 'about'), + typeId: asInt(json, 'type_id'), + isNsfw: asBool(json, 'is_nsfw'), + subscribers: asInt(json, 'subscribers'), + sumPending: asInt(json, 'sum_pending'), + admins: asList(json, 'admins').map((e) => e.toString()).toList(), + ); + + Map toJson() => { + 'id': id, + 'name': name, + 'title': title, + 'about': about, + 'type_id': typeId, + 'is_nsfw': isNsfw, + 'subscribers': subscribers, + 'sum_pending': sumPending, + 'admins': admins.map((e) => e), + }; +} + diff --git a/lib/src/screens/communities_screen/communities_screen.dart b/lib/src/screens/communities_screen/communities_screen.dart new file mode 100644 index 00000000..a37cc4cb --- /dev/null +++ b/lib/src/screens/communities_screen/communities_screen.dart @@ -0,0 +1,94 @@ +import 'dart:developer'; + +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/communities_models/request/communities_request_model.dart'; +import 'package:acela/src/models/communities_models/response/communities_response_models.dart'; +import 'package:acela/src/widgets/custom_circle_avatar.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:acela/src/widgets/retry.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; + +class CommunitiesScreen extends StatefulWidget { + const CommunitiesScreen({Key? key}) : super(key: key); + + @override + _CommunitiesScreenState createState() => _CommunitiesScreenState(); +} + +class _CommunitiesScreenState extends State { + Future> getData() async { + var client = http.Client(); + var body = communitiesRequestModelToJson( + CommunitiesRequestModel(params: CommunitiesRequestParams())); + var response = await client.post(Uri.parse(server.hiveDomain), body: body); + if (response.statusCode == 200) { + var communitiesResponse = + communitiesResponseModelFromString(response.body); + return communitiesResponse.result; + } else { + throw "Status code is ${response.statusCode}"; + } + } + + Widget _listTile(CommunityItem item) { + return ListTile( + leading: CustomCircleAvatar( + width: 60, + height: 60, + url: server.communityIcon(item.name), + ), + title: Text(item.title), + subtitle: Text(item.about), + onTap: () { + log("user tapped on ${item.name}"); + }, + ); + } + + Widget _list(List data) { + return ListView.separated( + itemBuilder: (context, index) { + return _listTile(data[index]); + }, + separatorBuilder: (context, index) => const Divider(), + itemCount: data.length); + } + + Widget _body() { + return FutureBuilder>( + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasError) { + return RetryScreen( + error: snapshot.error?.toString() ?? "Something went wrong", + onRetry: getData, + ); + } else if (snapshot.hasData) { + return Container( + margin: const EdgeInsets.only(top: 10, bottom: 10), + child: _list(snapshot.data!.take(100).toList()), + ); + } else { + return RetryScreen( + error: "Something went wrong", + onRetry: getData, + ); + } + } else { + return const LoadingScreen(); + } + }, + future: getData()); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Communities"), + ), + body: _body(), + ); + } +} diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index ab6d729b..e29f6bfe 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -41,11 +41,14 @@ class DrawerScreen extends StatelessWidget { ); } - Widget _communities() { + Widget _communities(BuildContext context) { return ListTile( leading: const Icon(Icons.people_sharp), title: const Text("Communities"), - onTap: () {}, + onTap: () { + Navigator.pop(context); + Navigator.of(context).pushNamed("/communities"); + }, ); } @@ -113,7 +116,7 @@ class DrawerScreen extends StatelessWidget { _divider(), _newContent(context), _divider(), - _communities(), + _communities(context), _divider(), _leaderBoard(context), _divider(), diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index cf5bd459..62fa5d72 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -2,8 +2,6 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; -import 'package:acela/src/models/video_details_model/video_details_description.dart'; -import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; import 'package:http/http.dart' show get; import 'package:http/http.dart' as http; From 5ebe89eac39c15ad3251ec2b53df822bf85bbcb7 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 11 Feb 2022 16:15:26 +0530 Subject: [PATCH 021/466] Draggable scrollable sheet experiments. --- .flutter-plugins-dependencies | 2 +- lib/src/screens/home_screen/home_screen.dart | 37 +++++++++++++------ .../home_screen/home_screen_widgets.dart | 29 +++++++++------ .../leaderboard_screen.dart | 3 -- 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index e46b4670..ce48706b 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-11 11:33:42.909732","version":"2.10.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-11 15:57:53.240980","version":"2.10.0"} \ No newline at end of file diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 53837232..7d2fa16a 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -46,21 +46,34 @@ class _HomeScreenState extends State { Navigator.of(context).pushNamed("/userChannel/${item.author}"); } + Widget header() { + if (vm.path.contains("userChannel")) { + return const SizedBox( + height: 10, + ); + } else { + return const SizedBox( + height: 0, + ); + } + } + Widget _screen() { return FutureBuilder( future: _loadingFeed, - builder: (builder, snapshot) { - if (snapshot.hasError) { - return RetryScreen( - error: snapshot.error?.toString() ?? 'Something went wrong', - onRetry: vm.loadHomeFeed); - } else if (snapshot.hasData) { - List items = snapshot.data! as List; - return widgets.list(items, vm.loadHomeFeed, onTap, onUserTap); - } else { - return widgets.loadingData(); - } - }); + builder: (builder, snapshot) { + if (snapshot.hasError) { + return RetryScreen( + error: snapshot.error?.toString() ?? 'Something went wrong', + onRetry: vm.loadHomeFeed); + } else if (snapshot.hasData) { + List items = snapshot.data! as List; + return widgets.list(items, vm.loadHomeFeed, onTap, onUserTap); + } else { + return widgets.loadingData(); + } + }, + ); } @override diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index 00a4993f..1a8027ab 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -42,21 +42,28 @@ class HomeScreenWidgets { Widget list(List list, Future Function() onRefresh, Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { - return Container( - padding: const EdgeInsets.only(top: 10, bottom: 10), - child: RefreshIndicator( - onRefresh: onRefresh, - child: ListView.separated( + return SizedBox.expand( + // padding: const EdgeInsets.only(top: 10, bottom: 10), + child: RefreshIndicator( + onRefresh: onRefresh, + child: DraggableScrollableSheet( + initialChildSize: 0.8, + minChildSize: 0.8, + maxChildSize: 1, + builder: (context, scrollController) { + return ListView.separated( + controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), itemBuilder: (context, index) { return _listTile(list[index], context, onTap, onUserTap); }, separatorBuilder: (context, index) => const Divider( - thickness: 0, - height: 10, - color: Colors.transparent, - ), - itemCount: list.length), - )); + thickness: 0, height: 1, color: Colors.transparent), + itemCount: list.length, + ); + }, + ), + ), + ); } } diff --git a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart index e661b850..d612225e 100644 --- a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart +++ b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart @@ -53,9 +53,6 @@ class _LeaderboardScreenState extends State { child: Text(medal), backgroundColor: Colors.transparent, ), - const SizedBox( - width: 5, - ), Text(item.username), ], ), From 0929826173fa3f62a52d938221bc6132cac136d0 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 15 Feb 2022 13:44:35 +0530 Subject: [PATCH 022/466] completed leaderboard as well as user channel. --- .flutter-plugins-dependencies | 2 +- .packages | 2 +- lib/src/screens/home_screen/home_screen.dart | 14 ++------ .../home_screen/home_screen_widgets.dart | 33 +++++++------------ .../leaderboard_screen.dart | 8 +++-- 5 files changed, 21 insertions(+), 38 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index ce48706b..0e3091b8 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-11 15:57:53.240980","version":"2.10.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-15 09:47:03.817741","version":"2.10.1"} \ No newline at end of file diff --git a/.packages b/.packages index 484639d4..48f751df 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-02-10 11:13:38.680297. +# Generated by pub on 2022-02-15 09:31:05.206051. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-34.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.2.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 7d2fa16a..e3ee976e 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -43,18 +43,8 @@ class _HomeScreenState extends State { } void onUserTap(HomeFeedItem item) { - Navigator.of(context).pushNamed("/userChannel/${item.author}"); - } - - Widget header() { - if (vm.path.contains("userChannel")) { - return const SizedBox( - height: 10, - ); - } else { - return const SizedBox( - height: 0, - ); + if (!widget.path.contains(item.author)) { + Navigator.of(context).pushNamed("/userChannel/${item.author}"); } } diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index 1a8027ab..1cc0fd24 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -42,28 +42,17 @@ class HomeScreenWidgets { Widget list(List list, Future Function() onRefresh, Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { - return SizedBox.expand( - // padding: const EdgeInsets.only(top: 10, bottom: 10), - child: RefreshIndicator( - onRefresh: onRefresh, - child: DraggableScrollableSheet( - initialChildSize: 0.8, - minChildSize: 0.8, - maxChildSize: 1, - builder: (context, scrollController) { - return ListView.separated( - controller: scrollController, - physics: const AlwaysScrollableScrollPhysics(), - itemBuilder: (context, index) { - return _listTile(list[index], context, onTap, onUserTap); - }, - separatorBuilder: (context, index) => const Divider( - thickness: 0, height: 1, color: Colors.transparent), - itemCount: list.length, - ); - }, - ), - ), + return RefreshIndicator( + onRefresh: onRefresh, + child:ListView.separated( + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (context, index) { + return _listTile(list[index], context, onTap, onUserTap); + }, + separatorBuilder: (context, index) => const Divider( + thickness: 0, height: 1, color: Colors.transparent), + itemCount: list.length, + ) ); } } diff --git a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart index d612225e..66796aab 100644 --- a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart +++ b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart @@ -40,6 +40,10 @@ class _LeaderboardScreenState extends State { ); } + void onUserTap(String author) { + Navigator.of(context).pushNamed("/userChannel/$author"); + } + Widget _medalTile(LeaderboardResponseItem item, String medal) { return ListTile( leading: CustomCircleAvatar( @@ -58,7 +62,7 @@ class _LeaderboardScreenState extends State { ), subtitle: _listTileSubtitle(item), onTap: () { - log("user tapped on ${item.username}"); + onUserTap(item.username); }, ); } @@ -73,7 +77,7 @@ class _LeaderboardScreenState extends State { title: Text(item.username), subtitle: _listTileSubtitle(item), onTap: () { - log("user tapped on ${item.username}"); + onUserTap(item.username); }, ); } From ef2b4fc974e6b4bdbde8bab9451c1b69528c05ff Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 17 Feb 2022 07:37:45 +0530 Subject: [PATCH 023/466] Feedback item - Drawer menu screen - Add Home menu item --- .firebase/hosting.YnVpbGQvd2Vi.cache | 28 ++++++++++-------- .flutter-plugins-dependencies | 2 +- .../screens/drawer_screen/drawer_screen.dart | 12 ++++++++ lib/src/widgets/video_player.dart | 29 ++++++++++--------- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/.firebase/hosting.YnVpbGQvd2Vi.cache b/.firebase/hosting.YnVpbGQvd2Vi.cache index 444573c3..666b2255 100644 --- a/.firebase/hosting.YnVpbGQvd2Vi.cache +++ b/.firebase/hosting.YnVpbGQvd2Vi.cache @@ -1,16 +1,20 @@ -favicon.png,1643821544168,a9fd35ee7a0d03fa369740142b0eadc6d794c7d94a3112a7d8fa5e1b9b00fe3f manifest.json,1643216912520,3b0da3b3b92dc0328b324ad0ad828f08f0d6807cb949b36f0ec722861759aacb -icons/Icon-192.png,1643821604698,4513a7b0bac37d1b6677f27b87f25c5f6f2dbcdad12ef49f43c1173788edd56d -icons/Icon-512.png,1643821631249,1e65fd7dc5ed1eaab6aae9fd5a18542a1ee5baabd0f52c094c62f3595aa00af5 -icons/Icon-maskable-192.png,1643821689292,3a402c33b814408a1d4e91f1e7afab7b85b76247bc9fd735eb2007273008f5c6 -icons/Icon-maskable-512.png,1643821670987,1a3f03a5d284c1bea6032c4bd42cc29f66504ada5351e1b161d8626af2f02c33 -flutter_service_worker.js,1644342899216,71536c7b0dcea8f23e015cd2ba090f7de598c0fee6c44e6c7e2af8ebf091c3c6 -index.html,1644342899117,2d954e87d5a7aab731258ff5e631a592272f763155dc2019d4fccc10137cbd6d -assets/AssetManifest.json,1644342899110,0b95630463cd2782488987ad923759f47cc68f73214c391ade6944d7a27c7560 -assets/FontManifest.json,1644342899110,2a26cf55926df210ccb9d713372cb114e0a12bf97104f6833e382566e2e7b16e -version.json,1644342899015,0a47060cfa5ce3c6a31fc65b7b255084deb121b4698df6016d27e58cb5cd20fc assets/assets/branding/three_speak_icon.png,1643216912507,2d8407594c7d199c572113bc3de8a90d268d7b791a86573ee237ca1af71148ca assets/assets/branding/three_speak_logo.png,1643216912507,3ac2dbaa31235a5df9a7b984903728f8d524eebcaedc9e9312fe69cc569b3700 -assets/NOTICES,1644342899110,c1ca890cf2497ad99773292837197c505ca33416e4d06dc7b5ae83ad22dd11b5 assets/fonts/MaterialIcons-Regular.otf,1615596762000,5f71a8843e4edc9656c39061c2232458a6fc77e1603305960e4efa9c77f8b7a2 -main.dart.js,1644342898796,e39a78595db0afd7fe60932fc8685684440913b5519c6d532f4329cd472f6acc +version.json,1644912965037,0a47060cfa5ce3c6a31fc65b7b255084deb121b4698df6016d27e58cb5cd20fc +assets/FontManifest.json,1644912965144,2a26cf55926df210ccb9d713372cb114e0a12bf97104f6833e382566e2e7b16e +favicon.png,1644471577919,a9fd35ee7a0d03fa369740142b0eadc6d794c7d94a3112a7d8fa5e1b9b00fe3f +flutter_service_worker.js,1644912965581,92a01f3f606088166a39ffae1b8f2d5d7b2a88cfd17f3ccfd004e55950579c8f +assets/AssetManifest.json,1644912965143,0b95630463cd2782488987ad923759f47cc68f73214c391ade6944d7a27c7560 +index.html,1644912965149,102d98cdc2bb54dab279019ca3cafe97eb41fb6dacdc96c32bd0002bf0e011d0 +icons/Icon-192.png,1644471577919,4513a7b0bac37d1b6677f27b87f25c5f6f2dbcdad12ef49f43c1173788edd56d +icons/Icon-maskable-192.png,1644471577920,3a402c33b814408a1d4e91f1e7afab7b85b76247bc9fd735eb2007273008f5c6 +canvaskit/canvaskit.js,315426600000,7070e00e23224440ff6333c831f4be11b9afd2d2b87b01753e524d4e8607edc8 +icons/Icon-512.png,1644471577920,1e65fd7dc5ed1eaab6aae9fd5a18542a1ee5baabd0f52c094c62f3595aa00af5 +icons/Icon-maskable-512.png,1644471577922,1a3f03a5d284c1bea6032c4bd42cc29f66504ada5351e1b161d8626af2f02c33 +canvaskit/profiling/canvaskit.js,315426600000,b64ecd48dbca34be0be9dceb61bd8a38dd24518ac0a70c4133553f9821bd0342 +assets/NOTICES,1644912965144,c1ca890cf2497ad99773292837197c505ca33416e4d06dc7b5ae83ad22dd11b5 +main.dart.js,1644912964550,7e4ca48c2670fa3d2e0534eeb8fc8ad5bc590a8c446c7eb739d2c853f01e84a0 +canvaskit/canvaskit.wasm,315426600000,20ad62ae701d503e645f826e0f28863b020ba8f3568a04dbfe349e52f2bb1f06 +canvaskit/profiling/canvaskit.wasm,315426600000,ae7385e32fe98cf31518919c377acc52a982a09758ef05fa5ec9c8bf069122ae diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 0e3091b8..708fc04b 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-15 09:47:03.817741","version":"2.10.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-16 16:04:48.710160","version":"2.10.1"} \ No newline at end of file diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index e29f6bfe..a871d0d2 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -8,6 +8,16 @@ class DrawerScreen extends StatelessWidget { final bool isDarkMode; final Function switchDarkMode; + Widget _homeMenu(BuildContext context) { + return ListTile( + leading: const Icon(Icons.home), + title: const Text("Home"), + onTap: () { + Navigator.pop(context); + }, + ); + } + Widget _firstUploads(BuildContext context) { return ListTile( leading: const Icon(Icons.emoji_emotions_outlined), @@ -110,6 +120,8 @@ class DrawerScreen extends StatelessWidget { return ListView( children: [ _drawerHeader(context), + _homeMenu(context), + _divider(), _firstUploads(context), _divider(), _trendingContent(context), diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index 96bfa799..20e52152 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -11,8 +11,10 @@ class SPKVideoPlayer extends StatefulWidget { _SPKVideoPlayerState createState() => _SPKVideoPlayerState(); } -class _SPKVideoPlayerState extends State with AutomaticKeepAliveClientMixin { +class _SPKVideoPlayerState extends State + with AutomaticKeepAliveClientMixin { late VideoPlayerController controller; + @override bool get wantKeepAlive => true; @@ -24,7 +26,8 @@ class _SPKVideoPlayerState extends State with AutomaticKeepAlive @override void initState() { - controller = VideoPlayerController.network(widget.playUrl) + controller = VideoPlayerController.network(widget.playUrl, + videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true)) ..initialize().then((_) { setState(() { controller.play(); @@ -38,17 +41,17 @@ class _SPKVideoPlayerState extends State with AutomaticKeepAlive return Center( child: controller.value.isInitialized ? AspectRatio( - aspectRatio: controller.value.aspectRatio, - child: Stack( - alignment: Alignment.bottomCenter, - children: [ - VideoPlayer(controller), - ClosedCaption(text: controller.value.caption.text), - ControlsOverlay(controller: controller), - VideoProgressIndicator(controller, allowScrubbing: true), - ], - ), - ) + aspectRatio: controller.value.aspectRatio, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + VideoPlayer(controller), + ClosedCaption(text: controller.value.caption.text), + ControlsOverlay(controller: controller), + VideoProgressIndicator(controller, allowScrubbing: true), + ], + ), + ) : const LoadingScreen(), ); } From 06a26abc41c3a69e7928a341c93e4a928616bb3c Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 17 Feb 2022 10:41:36 +0530 Subject: [PATCH 024/466] added video recommendations --- .flutter-plugins-dependencies | 2 +- .../video_recommendation.dart | 40 +++++++++++ .../video_details_comments.dart | 1 + .../video_details_recommendation.dart | 72 +++++++++++++++++++ .../video_details_screen.dart | 3 +- .../video_details_tabbed_widget.dart | 5 +- .../video_details_view_model.dart | 13 ++++ lib/src/widgets/list_tile_video.dart | 6 ++ lib/src/widgets/video_player.dart | 1 + 9 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 lib/src/models/video_recommendation_models/video_recommendation.dart create mode 100644 lib/src/screens/video_details_screen/video_details_recommendation.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 708fc04b..b936f3ef 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-16 16:04:48.710160","version":"2.10.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 08:24:03.583325","version":"2.10.1"} \ No newline at end of file diff --git a/lib/src/models/video_recommendation_models/video_recommendation.dart b/lib/src/models/video_recommendation_models/video_recommendation.dart new file mode 100644 index 00000000..93458f2f --- /dev/null +++ b/lib/src/models/video_recommendation_models/video_recommendation.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; +import 'package:acela/src/utils/safe_convert.dart'; + +List videoRecommendationItemsFromJson(String str) { + final jsonList = json.decode(str) as List; + return jsonList.map((e) => VideoRecommendationItem.fromJson(e)).toList(); +} + +class VideoRecommendationItem { + // https://img.3speakcontent.co/asxmrbot/poster.png + final String image; + // I am alive challenge day 131 // crossing the bridge + final String title; + // asxmrbot + final String mediaid; + // dobro2020 + final String owner; + + VideoRecommendationItem({ + this.image = "", + this.title = "", + this.mediaid = "", + this.owner = "", + }); + + factory VideoRecommendationItem.fromJson(Map? json) => VideoRecommendationItem( + image: asString(json, 'image'), + title: asString(json, 'title'), + mediaid: asString(json, 'mediaid'), + owner: asString(json, 'owner'), + ); + + Map toJson() => { + 'image': image, + 'title': title, + 'mediaid': mediaid, + 'owner': owner, + }; +} + diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart index 395efa83..3e2c7509 100644 --- a/lib/src/screens/video_details_screen/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -86,6 +86,7 @@ class _VideoDetailsCommentsWidgetState extends State @override Widget build(BuildContext context) { + super.build(context); return FutureBuilder( future: widget.vm.loadComments(widget.vm.author, widget.vm.permlink), builder: (builder, snapshot) { diff --git a/lib/src/screens/video_details_screen/video_details_recommendation.dart b/lib/src/screens/video_details_screen/video_details_recommendation.dart new file mode 100644 index 00000000..d94534b5 --- /dev/null +++ b/lib/src/screens/video_details_screen/video_details_recommendation.dart @@ -0,0 +1,72 @@ +import 'dart:developer'; +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/widgets/list_tile_video.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:flutter/material.dart'; + +class VideoDetailsRecommendationWidget extends StatefulWidget { + const VideoDetailsRecommendationWidget({Key? key, required this.vm}) + : super(key: key); + final VideoDetailsViewModel vm; + + @override + _VideoDetailsRecommendationWidgetState createState() => + _VideoDetailsRecommendationWidgetState(); +} + +class _VideoDetailsRecommendationWidgetState + extends State + with AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + + Widget listTile(VideoRecommendationItem item) { + return ListTileVideo( + placeholder: 'assets/branding/three_speak_logo.png', + url: item.image, + userThumbUrl: server.userOwnerThumb(item.owner), + title: item.title, + subtitle: "", + onUserTap: () { + log("Video recommendation item taped"); + }, + ); + } + + Widget recommendationsListView(List videos) { + return Container( + margin: const EdgeInsets.only(top: 10, bottom: 10), + child: ListView.separated( + itemBuilder: (context, index) { + return listTile(videos[index]); + }, + separatorBuilder: (context, index) => const Divider( + height: 10, + color: Colors.blueGrey, + ), + itemCount: videos.length), + ); + } + + @override + Widget build(BuildContext context) { + super.build(context); + return FutureBuilder( + future: widget.vm.getRecommendedVideos(), + builder: (builder, snapshot) { + if (snapshot.hasError) { + String text = + 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; + return Text(text); + } else if (snapshot.hasData) { + var data = snapshot.data! as List; + return recommendationsListView(data); + } else { + return const LoadingScreen(); + } + }, + ); + } +} diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 3ef9e914..04a625cc 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -1,13 +1,13 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_recommendation.dart'; import 'package:acela/src/screens/video_details_screen/video_details_tabbed_widget.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/video_player.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; -import 'package:http/http.dart'; class VideoDetailsScreen extends StatefulWidget { const VideoDetailsScreen({Key? key, required this.vm}) : super(key: key); @@ -54,6 +54,7 @@ class _VideoDetailsScreenState extends State { ), descriptionMarkDown(details.description), VideoDetailsCommentsWidget(vm: widget.vm), + VideoDetailsRecommendationWidget(vm: widget.vm), ]; } diff --git a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart index 65d12afe..6de43886 100644 --- a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart +++ b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart @@ -20,8 +20,9 @@ class _VideoDetailsTabbedWidgetState extends State with SingleTickerProviderStateMixin { static const List tabs = [ Tab(text: 'Video'), - Tab(text: 'Description'), - Tab(text: 'Comments') + Tab(text: 'Info'), + Tab(text: 'Comments'), + Tab(text: 'More'), ]; late TabController _tabController; diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index 62fa5d72..4e85cc7b 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -2,6 +2,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; +import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; import 'package:http/http.dart' show get; import 'package:http/http.dart' as http; @@ -59,6 +60,18 @@ class VideoDetailsViewModel { } } + Future> getRecommendedVideos() async { + final endPoint = + "${server.domain}/apiv2/recommended?v=$author/$permlink"; + var response = await get(Uri.parse(endPoint)); + if (response.statusCode == 200) { + var data = videoRecommendationItemsFromJson(response.body); + return data; + } else { + throw "Status code = ${response.statusCode}"; + } + } + Future> loadComments(String author, String permlink) async { var client = http.Client(); var body = diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index 65441fea..f8ab0fa6 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -65,6 +65,12 @@ class ListTileVideo extends StatelessWidget { placeholder: placeholder, image: server.resizedImage(url), fit: BoxFit.cover, + placeholderErrorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { + return Image.asset(placeholder); + }, + imageErrorBuilder: (BuildContext context, Object error, StackTrace? stackTrace){ + return Image.asset(placeholder); + }, ), Container( padding: const EdgeInsets.all(10), diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index 20e52152..d16640a8 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -38,6 +38,7 @@ class _SPKVideoPlayerState extends State @override Widget build(BuildContext context) { + super.build(context); return Center( child: controller.value.isInitialized ? AspectRatio( From f25c7388306bafd37f3d713a8244050de4bccf4a Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 17 Feb 2022 11:18:03 +0530 Subject: [PATCH 025/466] Navigation to user-channel and video details from recommendations. --- .flutter-plugins-dependencies | 2 +- .idea/runConfigurations/main_dart.xml | 3 ++- .../video_details_recommendation.dart | 23 ++++++++++++------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index b936f3ef..1c4fe9c2 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 08:24:03.583325","version":"2.10.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 10:46:50.607089","version":"2.10.1"} \ No newline at end of file diff --git a/.idea/runConfigurations/main_dart.xml b/.idea/runConfigurations/main_dart.xml index aab7b5cd..dcb3d7b2 100644 --- a/.idea/runConfigurations/main_dart.xml +++ b/.idea/runConfigurations/main_dart.xml @@ -1,6 +1,7 @@ + \ No newline at end of file diff --git a/lib/src/screens/video_details_screen/video_details_recommendation.dart b/lib/src/screens/video_details_screen/video_details_recommendation.dart index d94534b5..b1321018 100644 --- a/lib/src/screens/video_details_screen/video_details_recommendation.dart +++ b/lib/src/screens/video_details_screen/video_details_recommendation.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:acela/src/widgets/loading_screen.dart'; @@ -23,14 +24,20 @@ class _VideoDetailsRecommendationWidgetState bool get wantKeepAlive => true; Widget listTile(VideoRecommendationItem item) { - return ListTileVideo( - placeholder: 'assets/branding/three_speak_logo.png', - url: item.image, - userThumbUrl: server.userOwnerThumb(item.owner), - title: item.title, - subtitle: "", - onUserTap: () { - log("Video recommendation item taped"); + return ListTile( + title: ListTileVideo( + placeholder: 'assets/branding/three_speak_logo.png', + url: item.image, + userThumbUrl: server.userOwnerThumb(item.owner), + title: item.title, + subtitle: "", + onUserTap: () { + Navigator.of(context).pushNamed("/userChannel/${item.owner}"); + }, + ), + onTap: () { + Navigator.of(context) + .pushNamed(VideoDetailsScreen.routeName(item.owner, item.mediaid)); }, ); } From 46916a279bbc64c6cb01b740e07fa011d3d9adc3 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 17 Feb 2022 12:49:27 +0530 Subject: [PATCH 026/466] added volume control --- .flutter-plugins-dependencies | 2 +- lib/src/widgets/controls_overlay.dart | 91 +++++++++++++++++---------- 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 1c4fe9c2..424a5a73 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 10:46:50.607089","version":"2.10.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 12:30:51.927323","version":"2.10.1"} \ No newline at end of file diff --git a/lib/src/widgets/controls_overlay.dart b/lib/src/widgets/controls_overlay.dart index b0a42ad1..e875bb54 100644 --- a/lib/src/widgets/controls_overlay.dart +++ b/lib/src/widgets/controls_overlay.dart @@ -1,10 +1,16 @@ import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; -class ControlsOverlay extends StatelessWidget { - const ControlsOverlay({Key? key, required this.controller}) - : super(key: key); +class ControlsOverlay extends StatefulWidget { + const ControlsOverlay({Key? key, required this.controller}) : super(key: key); + final VideoPlayerController controller; + + @override + _ControlsOverlayState createState() => _ControlsOverlayState(); +} + +class _ControlsOverlayState extends State { static const _examplePlaybackRates = [ 0.5, 1.0, @@ -12,7 +18,8 @@ class ControlsOverlay extends StatelessWidget { 2.0, ]; - final VideoPlayerController controller; + var volume = 1.0; + var playing = true; @override Widget build(BuildContext context) { @@ -21,7 +28,7 @@ class ControlsOverlay extends StatelessWidget { AnimatedSwitcher( duration: const Duration(milliseconds: 50), reverseDuration: const Duration(milliseconds: 200), - child: controller.value.isPlaying + child: playing ? const SizedBox.shrink() : Container( color: Colors.black26, @@ -37,37 +44,57 @@ class ControlsOverlay extends StatelessWidget { ), GestureDetector( onTap: () { - controller.value.isPlaying ? controller.pause() : controller.play(); + setState(() { + widget.controller.value.isPlaying + ? widget.controller.pause() + : widget.controller.play(); + playing = widget.controller.value.isPlaying; + }); }, ), - Align( - alignment: Alignment.topRight, - child: PopupMenuButton( - initialValue: controller.value.playbackSpeed, - tooltip: 'Playback speed', - onSelected: (speed) { - controller.setPlaybackSpeed(speed); - }, - itemBuilder: (context) { - return [ - for (final speed in _examplePlaybackRates) - PopupMenuItem( - value: speed, - child: Text('${speed}x'), - ) - ]; - }, - child: Padding( - padding: const EdgeInsets.symmetric( - // Using less vertical padding as the text is also longer - // horizontally, so it feels like it would need more spacing - // horizontally (matching the aspect ratio of the video). - vertical: 12, - horizontal: 16, + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const Spacer(), + SizedBox( + height: 30, + child: Slider( + value: volume, + onChanged: (value) { + setState(() { + volume = value; + widget.controller.setVolume(value); + }); + }, ), - child: Text('${controller.value.playbackSpeed}x'), ), - ), + PopupMenuButton( + initialValue: widget.controller.value.playbackSpeed, + tooltip: 'Playback speed', + onSelected: (speed) { + widget.controller.setPlaybackSpeed(speed); + }, + itemBuilder: (context) { + return [ + for (final speed in _examplePlaybackRates) + PopupMenuItem( + value: speed, + child: Text('${speed}x'), + ) + ]; + }, + child: Padding( + padding: const EdgeInsets.symmetric( + // Using less vertical padding as the text is also longer + // horizontally, so it feels like it would need more spacing + // horizontally (matching the aspect ratio of the video). + vertical: 12, + horizontal: 16, + ), + child: Text('${widget.controller.value.playbackSpeed}x'), + ), + ) + ], ), ], ); From b43b828671dae9bfb5e071e3b8375cf709355edc Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 17 Feb 2022 13:23:01 +0530 Subject: [PATCH 027/466] =?UTF-8?q?-=20Add=20full=20screen=20button=20?= =?UTF-8?q?=E2=9C=85=20-=20Volume=20controls=20=E2=9C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .flutter-plugins-dependencies | 2 +- .../video_details_screen.dart | 68 +++++++---- .../video_details_tabbed_widget.dart | 44 +++---- lib/src/widgets/controls_overlay.dart | 111 +++++++++++------- lib/src/widgets/video_player.dart | 18 ++- 5 files changed, 149 insertions(+), 94 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 424a5a73..1f46df83 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 12:30:51.927323","version":"2.10.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 13:03:29.753175","version":"2.10.1"} \ No newline at end of file diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 04a625cc..3795e00a 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -22,18 +22,25 @@ class VideoDetailsScreen extends StatefulWidget { } class _VideoDetailsScreenState extends State { + var fullscreen = false; + void onUserTap() { Navigator.of(context).pushNamed("/userChannel/${widget.vm.author}"); } Widget container(String title, Widget body) { return Scaffold( - appBar: AppBar( - title: Text(title), - actions: [ - IconButton(onPressed: onUserTap, icon: const Icon(Icons.person)), - ], - ), + appBar: fullscreen + ? null + : AppBar( + title: Text(title), + actions: [ + IconButton( + onPressed: onUserTap, + icon: const Icon(Icons.person), + ), + ], + ), body: body, ); } @@ -51,6 +58,11 @@ class _VideoDetailsScreenState extends State { return [ SPKVideoPlayer( playUrl: details.playUrl, + handleFullScreen: (value) { + setState(() { + fullscreen = value; + }); + }, ), descriptionMarkDown(details.description), VideoDetailsCommentsWidget(vm: widget.vm), @@ -61,27 +73,31 @@ class _VideoDetailsScreenState extends State { @override Widget build(BuildContext context) { return FutureBuilder( - future: widget.vm.getVideoDetails(), - builder: (builder, snapshot) { - if (snapshot.hasError) { - String text = - 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; - return container(widget.vm.author, Text(text)); - } else if (snapshot.hasData) { - var data = snapshot.data as VideoDetails?; - if (data != null) { - return VideoDetailsTabbedWidget( - children: tabBarChildren(data), - title: data.title, - onUserTap: onUserTap, - ); - } else { - return container( - widget.vm.author, const Text("Something went wrong")); - } + future: widget.vm.getVideoDetails(), + builder: (builder, snapshot) { + if (snapshot.hasError) { + String text = + 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; + return container(widget.vm.author, Text(text)); + } else if (snapshot.hasData) { + var data = snapshot.data as VideoDetails?; + if (data != null) { + return VideoDetailsTabbedWidget( + children: tabBarChildren(data), + title: data.title, + onUserTap: onUserTap, + fullscreen: fullscreen, + ); } else { - return container(widget.vm.author, const LoadingScreen()); + return container( + widget.vm.author, + const Text("Something went wrong"), + ); } - }); + } else { + return container(widget.vm.author, const LoadingScreen()); + } + }, + ); } } diff --git a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart index 6de43886..88003384 100644 --- a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart +++ b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart @@ -1,15 +1,17 @@ import 'package:flutter/material.dart'; class VideoDetailsTabbedWidget extends StatefulWidget { - const VideoDetailsTabbedWidget( - {Key? key, - required this.children, - required this.title, - required this.onUserTap}) - : super(key: key); + const VideoDetailsTabbedWidget({ + Key? key, + required this.children, + required this.title, + required this.onUserTap, + required this.fullscreen, + }) : super(key: key); final List children; final String title; final Function onUserTap; + final bool fullscreen; @override _VideoDetailsTabbedWidgetState createState() => @@ -42,20 +44,22 @@ class _VideoDetailsTabbedWidgetState extends State @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text(widget.title), - actions: [ - IconButton( - onPressed: () { - widget.onUserTap(); - }, - icon: const Icon(Icons.person)), - ], - bottom: TabBar( - controller: _tabController, - tabs: tabs, - ), - ), + appBar: widget.fullscreen + ? null + : AppBar( + title: Text(widget.title), + actions: [ + IconButton( + onPressed: () { + widget.onUserTap(); + }, + icon: const Icon(Icons.person)), + ], + bottom: TabBar( + controller: _tabController, + tabs: tabs, + ), + ), body: TabBarView( controller: _tabController, children: widget.children, diff --git a/lib/src/widgets/controls_overlay.dart b/lib/src/widgets/controls_overlay.dart index e875bb54..8ae2dcbc 100644 --- a/lib/src/widgets/controls_overlay.dart +++ b/lib/src/widgets/controls_overlay.dart @@ -2,9 +2,12 @@ import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; class ControlsOverlay extends StatefulWidget { - const ControlsOverlay({Key? key, required this.controller}) : super(key: key); + const ControlsOverlay( + {Key? key, required this.controller, required this.handleFullScreen}) + : super(key: key); final VideoPlayerController controller; + final Function(bool) handleFullScreen; @override _ControlsOverlayState createState() => _ControlsOverlayState(); @@ -20,6 +23,7 @@ class _ControlsOverlayState extends State { var volume = 1.0; var playing = true; + var fullScreen = false; @override Widget build(BuildContext context) { @@ -52,50 +56,69 @@ class _ControlsOverlayState extends State { }); }, ), - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - const Spacer(), - SizedBox( - height: 30, - child: Slider( - value: volume, - onChanged: (value) { - setState(() { - volume = value; - widget.controller.setVolume(value); - }); - }, - ), - ), - PopupMenuButton( - initialValue: widget.controller.value.playbackSpeed, - tooltip: 'Playback speed', - onSelected: (speed) { - widget.controller.setPlaybackSpeed(speed); - }, - itemBuilder: (context) { - return [ - for (final speed in _examplePlaybackRates) - PopupMenuItem( - value: speed, - child: Text('${speed}x'), - ) - ]; - }, - child: Padding( - padding: const EdgeInsets.symmetric( - // Using less vertical padding as the text is also longer - // horizontally, so it feels like it would need more spacing - // horizontally (matching the aspect ratio of the video). - vertical: 12, - horizontal: 16, - ), - child: Text('${widget.controller.value.playbackSpeed}x'), + Align( + alignment: Alignment.bottomLeft, + child: Column( + children: [ + const Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + height: 30, + child: Slider( + value: volume, + onChanged: (value) { + setState(() { + volume = value; + widget.controller.setVolume(value); + }); + }, + ), + ), + IconButton( + onPressed: () { + setState(() { + fullScreen = !fullScreen; + widget.handleFullScreen(fullScreen); + }); + }, + icon: fullScreen + ? const Icon(Icons.fullscreen) + : const Icon(Icons.fullscreen_exit), + ), + PopupMenuButton( + initialValue: widget.controller.value.playbackSpeed, + tooltip: 'Playback speed', + onSelected: (speed) { + widget.controller.setPlaybackSpeed(speed); + }, + itemBuilder: (context) { + return [ + for (final speed in _examplePlaybackRates) + PopupMenuItem( + value: speed, + child: Text('${speed}x'), + ) + ]; + }, + child: Padding( + padding: const EdgeInsets.symmetric( + // Using less vertical padding as the text is also longer + // horizontally, so it feels like it would need more spacing + // horizontally (matching the aspect ratio of the video). + vertical: 12, + horizontal: 16, + ), + child: Text('${widget.controller.value.playbackSpeed}x'), + ), + ) + ], ), - ) - ], - ), + const SizedBox(height: 40), + ], + ), + ) ], ); } diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index d16640a8..c03817f0 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -4,8 +4,11 @@ import 'package:video_player/video_player.dart'; import 'package:acela/src/widgets/controls_overlay.dart'; class SPKVideoPlayer extends StatefulWidget { - const SPKVideoPlayer({Key? key, required this.playUrl}) : super(key: key); + const SPKVideoPlayer( + {Key? key, required this.playUrl, required this.handleFullScreen}) + : super(key: key); final String playUrl; + final Function(bool) handleFullScreen; @override _SPKVideoPlayerState createState() => _SPKVideoPlayerState(); @@ -48,8 +51,17 @@ class _SPKVideoPlayerState extends State children: [ VideoPlayer(controller), ClosedCaption(text: controller.value.caption.text), - ControlsOverlay(controller: controller), - VideoProgressIndicator(controller, allowScrubbing: true), + ControlsOverlay( + controller: controller, + handleFullScreen: (value) { + widget.handleFullScreen(value); + }, + ), + VideoProgressIndicator( + controller, + allowScrubbing: true, + padding: const EdgeInsets.all(20), + ), ], ), ) From 926ebcfba4fba18528e2e4adda09679c4f2a9e5e Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 17 Feb 2022 13:45:25 +0530 Subject: [PATCH 028/466] updated plugins --- .flutter-plugins | 8 ++++---- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 32 +++++++++++------------------ .idea/libraries/Flutter_Plugins.xml | 8 ++++---- .packages | 15 +++++++------- pubspec.lock | 19 ++++++----------- 6 files changed, 34 insertions(+), 50 deletions(-) diff --git a/.flutter-plugins b/.flutter-plugins index 7800a1de..4d9ee463 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -2,7 +2,7 @@ firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/ firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/ video_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.18/ -video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/ -video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/ -video_player_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/ -video_player_web_hls=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/ +video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/ +video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/ +video_player_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/ +video_player_web_hls=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 1f46df83..c8955fda 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 13:03:29.753175","version":"2.10.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 13:23:45.527248","version":"2.10.1"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index ed93ca50..df38851f 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -285,7 +285,7 @@ - @@ -387,13 +387,6 @@ - - - - - - @@ -544,35 +537,35 @@ - - - - - @@ -637,7 +630,7 @@ - + @@ -652,7 +645,6 @@ - @@ -673,11 +665,11 @@ - - - - - + + + + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index e13d2de3..9425abe4 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,13 +1,13 @@ - - - - + + + + diff --git a/.packages b/.packages index 48f751df..8067b18f 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-02-15 09:31:05.206051. +# Generated by pub on 2022-02-17 13:23:45.309985. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-34.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.2.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ @@ -44,7 +44,7 @@ glob:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/glo graphs:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/graphs-2.1.0/lib/ html:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/html-0.15.0/lib/ http:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http-0.13.4/lib/ -http_multi_server:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_multi_server-3.0.1/lib/ +http_multi_server:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_multi_server-3.2.0/lib/ http_parser:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_parser-4.0.0/lib/ io:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/io-1.0.3/lib/ js:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3/lib/ @@ -59,7 +59,6 @@ meta:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/met mime:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/mime-1.0.1/lib/ package_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_config-2.0.2/lib/ path:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.0/lib/ -pedantic:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pedantic-1.11.1/lib/ plugin_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2/lib/ pool:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pool-1.5.0/lib/ pub_semver:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pub_semver-2.1.0/lib/ @@ -81,11 +80,11 @@ timing:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/t typed_data:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib/ vector_math:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.1/lib/ video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.18/lib/ -video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.2.17/lib/ -video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.2.18/lib/ -video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-4.2.0/lib/ -video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.6/lib/ -video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+3/lib/ +video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/lib/ +video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/lib/ +video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.0/lib/ +video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/lib/ +video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/lib/ watcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/watcher-1.0.1/lib/ web_socket_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.1.0/lib/ yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/yaml-3.1.0/lib/ diff --git a/pubspec.lock b/pubspec.lock index 0bcb90fb..f8d10a95 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -281,7 +281,7 @@ packages: name: http_multi_server url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.2.0" http_parser: dependency: transitive description: @@ -380,13 +380,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.1" plugin_platform_interface: dependency: transitive description: @@ -538,35 +531,35 @@ packages: name: video_player_android url: "https://pub.dartlang.org" source: hosted - version: "2.2.17" + version: "2.3.0" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation url: "https://pub.dartlang.org" source: hosted - version: "2.2.18" + version: "2.3.0" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "4.2.0" + version: "5.1.0" video_player_web: dependency: transitive description: name: video_player_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.6" + version: "2.0.7" video_player_web_hls: dependency: "direct main" description: name: video_player_web_hls url: "https://pub.dartlang.org" source: hosted - version: "0.1.11+3" + version: "0.1.11+4" watcher: dependency: transitive description: From 378aa9c01b9600e8493f84aa58a4b5b5be761c99 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 17 Feb 2022 14:01:31 +0530 Subject: [PATCH 029/466] added support for links. --- .flutter-plugins | 7 ++ .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 64 +++++++++++++++++++ .idea/libraries/Flutter_Plugins.xml | 7 ++ .packages | 10 ++- lib/generated_plugin_registrant.dart | 2 + .../video_details_screen.dart | 6 +- pubspec.lock | 58 ++++++++++++++++- pubspec.yaml | 1 + 9 files changed, 153 insertions(+), 4 deletions(-) diff --git a/.flutter-plugins b/.flutter-plugins index 4d9ee463..c1cb4ae4 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,6 +1,13 @@ # This is a generated file; do not edit or check into version control. firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/ firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/ +url_launcher=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.20/ +url_launcher_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/ +url_launcher_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/ +url_launcher_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/ +url_launcher_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/ +url_launcher_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/ +url_launcher_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/ video_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.18/ video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/ video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index c8955fda..4cdf7b9a 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 13:23:45.527248","version":"2.10.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 14:00:34.412482","version":"2.10.1"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index df38851f..be97c954 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -520,6 +520,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -663,6 +719,14 @@ + + + + + + + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 9425abe4..5f0fd73f 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -8,6 +8,13 @@ + + + + + + + diff --git a/.packages b/.packages index 8067b18f..c247b032 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-02-17 13:23:45.309985. +# Generated by pub on 2022-02-17 14:00:24.784798. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-34.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.2.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ @@ -78,6 +78,14 @@ test_api:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org timeago:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timeago-3.2.2/lib/ timing:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timing-1.0.0/lib/ typed_data:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib/ +url_launcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.20/lib/ +url_launcher_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/lib/ +url_launcher_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/lib/ +url_launcher_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/lib/ +url_launcher_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/lib/ +url_launcher_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_platform_interface-2.0.5/lib/ +url_launcher_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/lib/ +url_launcher_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/lib/ vector_math:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.1/lib/ video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.18/lib/ video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/lib/ diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart index 7552fd6b..48c36af8 100644 --- a/lib/generated_plugin_registrant.dart +++ b/lib/generated_plugin_registrant.dart @@ -6,6 +6,7 @@ // ignore_for_file: lines_longer_than_80_chars import 'package:firebase_core_web/firebase_core_web.dart'; +import 'package:url_launcher_web/url_launcher_web.dart'; import 'package:video_player_web/video_player_web.dart'; import 'package:video_player_web_hls/video_player_web_hls.dart'; @@ -14,6 +15,7 @@ import 'package:flutter_web_plugins/flutter_web_plugins.dart'; // ignore: public_member_api_docs void registerPlugins(Registrar registrar) { FirebaseCoreWeb.registerWith(registrar); + UrlLauncherPlugin.registerWith(registrar); VideoPlayerPlugin.registerWith(registrar); VideoPlayerPluginHls.registerWith(registrar); registrar.registerMessageHandler(); diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 3795e00a..a7d56734 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -1,4 +1,3 @@ -import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; import 'package:acela/src/screens/video_details_screen/video_details_recommendation.dart'; @@ -8,6 +7,7 @@ import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/video_player.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:url_launcher/url_launcher.dart'; class VideoDetailsScreen extends StatefulWidget { const VideoDetailsScreen({Key? key, required this.vm}) : super(key: key); @@ -50,7 +50,11 @@ class _VideoDetailsScreenState extends State { margin: const EdgeInsets.all(10), child: Markdown( data: markDown, + onTapLink: (text, url, title) { + launch(url!); + }, ), + // Html(data: markdownToHtml(markDown)), ); } diff --git a/pubspec.lock b/pubspec.lock index f8d10a95..9258f6bc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -511,6 +511,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.20" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.15" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.15" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.8" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" vector_math: dependency: transitive description: @@ -583,4 +639,4 @@ packages: version: "3.1.0" sdks: dart: ">=2.15.1 <3.0.0" - flutter: ">=2.8.0" + flutter: ">=2.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index effd30c3..dba1f345 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: http: ^0.13.4 json_annotation: ^4.4.0 timeago: ^3.1.0 + url_launcher: ^6.0.20 video_player: ^2.2.14 video_player_web_hls: ^0.1.11+3 From a12a8889b3e497f71caf82a90aa03903597bfe12 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 17 Feb 2022 14:02:40 +0530 Subject: [PATCH 030/466] added support for links in comments. --- .../screens/video_details_screen/video_details_comments.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart index 3e2c7509..74ac807c 100644 --- a/lib/src/screens/video_details_screen/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -6,6 +6,7 @@ import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:timeago/timeago.dart' as timeago; +import 'package:url_launcher/url_launcher.dart'; class VideoDetailsCommentsWidget extends StatefulWidget { const VideoDetailsCommentsWidget( @@ -52,6 +53,9 @@ class _VideoDetailsCommentsWidgetState extends State MarkdownBody( data: body, shrinkWrap: true, + onTapLink: (text, url, title) { + launch(url!); + }, ), Container(margin: const EdgeInsets.only(bottom: 10)), Text( From d332a875d56bf6ca0753ae3bef196e31b9cc8754 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 22 Feb 2022 15:34:58 +0530 Subject: [PATCH 031/466] =?UTF-8?q?2.=20video=20player=20-=20hide=20contro?= =?UTF-8?q?ls=20while=20playing=20-=20=E2=9C=85=204.=20find=20HTML=20rende?= =?UTF-8?q?rer=20-=20research=20-=20or=20remove=20html=20from=20the=20cont?= =?UTF-8?q?ent.=20=E2=9C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .flutter-plugins-dependencies | 2 +- .packages | 2 +- ios/Podfile.lock | 6 ++++++ .../video_details_screen/video_details_comments.dart | 3 ++- .../video_details_recommendation.dart | 1 - .../video_details_screen/video_details_screen.dart | 3 ++- .../video_details_tabbed_widget.dart | 5 +++-- lib/src/utils/seconds_to_duration.dart | 10 ++++++++++ lib/src/widgets/controls_overlay.dart | 4 ++-- 9 files changed, 27 insertions(+), 9 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 4cdf7b9a..9f236c48 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-17 14:00:34.412482","version":"2.10.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-22 15:17:26.386105","version":"2.10.2"} \ No newline at end of file diff --git a/.packages b/.packages index c247b032..983bd77e 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-02-17 14:00:24.784798. +# Generated by pub on 2022-02-22 06:15:29.441004. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-34.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.2.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6ae4ff08..fcc80571 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -28,12 +28,15 @@ PODS: - nanopb/decode (2.30908.0) - nanopb/encode (2.30908.0) - PromisesObjC (2.0.0) + - url_launcher_ios (0.0.1): + - Flutter - video_player_avfoundation (0.0.1): - Flutter DEPENDENCIES: - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - Flutter (from `Flutter`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) SPEC REPOS: @@ -51,6 +54,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/firebase_core/ios" Flutter: :path: Flutter + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" video_player_avfoundation: :path: ".symlinks/plugins/video_player_avfoundation/ios" @@ -64,6 +69,7 @@ SPEC CHECKSUMS: GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 + url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff PODFILE CHECKSUM: 56099e53bf102df458f588dbe78632cd13d5357b diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart index 74ac807c..f236f43e 100644 --- a/lib/src/screens/video_details_screen/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -1,6 +1,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; @@ -51,7 +52,7 @@ class _VideoDetailsCommentsWidgetState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ MarkdownBody( - data: body, + data: Utilities.removeAllHtmlTags(body), shrinkWrap: true, onTapLink: (text, url, title) { launch(url!); diff --git a/lib/src/screens/video_details_screen/video_details_recommendation.dart b/lib/src/screens/video_details_screen/video_details_recommendation.dart index b1321018..4a3a1614 100644 --- a/lib/src/screens/video_details_screen/video_details_recommendation.dart +++ b/lib/src/screens/video_details_screen/video_details_recommendation.dart @@ -1,4 +1,3 @@ -import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index a7d56734..143b5629 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -3,6 +3,7 @@ import 'package:acela/src/screens/video_details_screen/video_details_comments.da import 'package:acela/src/screens/video_details_screen/video_details_recommendation.dart'; import 'package:acela/src/screens/video_details_screen/video_details_tabbed_widget.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/video_player.dart'; import 'package:flutter/material.dart'; @@ -49,7 +50,7 @@ class _VideoDetailsScreenState extends State { return Container( margin: const EdgeInsets.all(10), child: Markdown( - data: markDown, + data: Utilities.removeAllHtmlTags(markDown), onTapLink: (text, url, title) { launch(url!); }, diff --git a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart index 88003384..9c2deb5a 100644 --- a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart +++ b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart @@ -22,9 +22,9 @@ class _VideoDetailsTabbedWidgetState extends State with SingleTickerProviderStateMixin { static const List tabs = [ Tab(text: 'Video'), - Tab(text: 'Info'), + Tab(text: 'Description'), Tab(text: 'Comments'), - Tab(text: 'More'), + Tab(text: 'Recommendation'), ]; late TabController _tabController; @@ -57,6 +57,7 @@ class _VideoDetailsTabbedWidgetState extends State ], bottom: TabBar( controller: _tabController, + isScrollable: true, tabs: tabs, ), ), diff --git a/lib/src/utils/seconds_to_duration.dart b/lib/src/utils/seconds_to_duration.dart index b666ebb5..caeef4fb 100644 --- a/lib/src/utils/seconds_to_duration.dart +++ b/lib/src/utils/seconds_to_duration.dart @@ -3,4 +3,14 @@ class Utilities { static String formatTime(int seconds) { return '${(Duration(seconds: seconds))}'.split('.')[0].padLeft(8, '0'); } + + static String removeAllHtmlTags(String htmlText) { + RegExp exp = RegExp( + r"<[^>]*>", + multiLine: true, + caseSensitive: true + ); + + return htmlText.replaceAll(exp, ''); + } } \ No newline at end of file diff --git a/lib/src/widgets/controls_overlay.dart b/lib/src/widgets/controls_overlay.dart index 8ae2dcbc..5fad9144 100644 --- a/lib/src/widgets/controls_overlay.dart +++ b/lib/src/widgets/controls_overlay.dart @@ -56,7 +56,7 @@ class _ControlsOverlayState extends State { }); }, ), - Align( + playing ? Container() : Align( alignment: Alignment.bottomLeft, child: Column( children: [ @@ -65,7 +65,7 @@ class _ControlsOverlayState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( - height: 30, + height: 20, child: Slider( value: volume, onChanged: (value) { From aea3f20159b8f763cbaa1f127cb1b4c5cdf9b609 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 22 Feb 2022 16:43:48 +0530 Subject: [PATCH 032/466] chewie player --- .flutter-plugins | 3 + .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 96 ++++++++++++++++++++++++++++ .idea/libraries/Flutter_Plugins.xml | 3 + .packages | 14 +++- acela.iml | 6 ++ ios/Podfile.lock | 6 ++ lib/generated_plugin_registrant.dart | 2 + lib/src/widgets/video_player.dart | 69 +++++++++++--------- pubspec.lock | 84 ++++++++++++++++++++++++ pubspec.yaml | 1 + 11 files changed, 255 insertions(+), 31 deletions(-) diff --git a/.flutter-plugins b/.flutter-plugins index c1cb4ae4..66c8c031 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -13,3 +13,6 @@ video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlan video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/ video_player_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/ video_player_web_hls=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/ +wakelock=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/ +wakelock_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/ +wakelock_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 9f236c48..a6237fd2 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]}],"date_created":"2022-02-22 15:17:26.386105","version":"2.10.2"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-02-22 16:41:53.269657","version":"2.10.2"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index be97c954..d7710845 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -114,6 +114,13 @@ + + + + + + @@ -163,6 +170,13 @@ + + + + + + @@ -177,6 +191,13 @@ + + + + + + @@ -373,6 +394,13 @@ + + + + + + @@ -401,6 +429,13 @@ + + + + + + @@ -583,6 +618,13 @@ + + + + + + @@ -625,6 +667,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -639,6 +716,13 @@ + + + + + + @@ -665,6 +749,7 @@ + @@ -672,8 +757,10 @@ + + @@ -699,10 +786,12 @@ + + @@ -728,14 +817,21 @@ + + + + + + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 5f0fd73f..a00db83c 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -15,6 +15,9 @@ + + + diff --git a/.packages b/.packages index 983bd77e..2b0999dd 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-02-22 06:15:29.441004. +# Generated by pub on 2022-02-22 16:17:43.777581. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-34.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.2.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ @@ -20,6 +20,7 @@ built_value:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang. characters:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib/ charcode:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib/ checked_yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/checked_yaml-2.0.1/lib/ +chewie:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/chewie-1.3.0/lib/ cli_util:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cli_util-0.3.5/lib/ clock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib/ code_builder:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/code_builder-4.1.0/lib/ @@ -27,8 +28,10 @@ collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.o convert:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/convert-3.0.1/lib/ crypto:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.1/lib/ csslib:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.17.1/lib/ +cupertino_icons:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.4/lib/ dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.1/lib/ fake_async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0/lib/ +ffi:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.1.2/lib/ file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib/ firebase_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/lib/ firebase_core_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_platform_interface-4.2.4/lib/ @@ -57,10 +60,12 @@ matcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ material_color_utilities:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.3/lib/ meta:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib/ mime:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/mime-1.0.1/lib/ +nested:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/nested-1.0.0/lib/ package_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_config-2.0.2/lib/ path:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.0/lib/ plugin_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2/lib/ pool:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pool-1.5.0/lib/ +provider:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/provider-6.0.2/lib/ pub_semver:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pub_semver-2.1.0/lib/ pubspec_parse:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pubspec_parse-1.2.0/lib/ shelf:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.2.0/lib/ @@ -87,13 +92,20 @@ url_launcher_platform_interface:file:///Applications/flutter/flutter/.pub-cache/ url_launcher_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/lib/ url_launcher_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/lib/ vector_math:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.1/lib/ +very_good_analysis:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/very_good_analysis-2.4.0/lib/ video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.18/lib/ video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/lib/ video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/lib/ video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.0/lib/ video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/lib/ video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/lib/ +wakelock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/lib/ +wakelock_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/lib/ +wakelock_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_platform_interface-0.3.0/lib/ +wakelock_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/lib/ +wakelock_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_windows-0.2.0/lib/ watcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/watcher-1.0.1/lib/ web_socket_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.1.0/lib/ +win32:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/win32-2.4.1/lib/ yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/yaml-3.1.0/lib/ acela:lib/ diff --git a/acela.iml b/acela.iml index 8c22ddee..6d20190f 100644 --- a/acela.iml +++ b/acela.iml @@ -66,6 +66,12 @@ + + + + + + diff --git a/ios/Podfile.lock b/ios/Podfile.lock index fcc80571..ddb317c5 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -32,12 +32,15 @@ PODS: - Flutter - video_player_avfoundation (0.0.1): - Flutter + - wakelock (0.0.1): + - Flutter DEPENDENCIES: - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - Flutter (from `Flutter`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) + - wakelock (from `.symlinks/plugins/wakelock/ios`) SPEC REPOS: trunk: @@ -58,6 +61,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/url_launcher_ios/ios" video_player_avfoundation: :path: ".symlinks/plugins/video_player_avfoundation/ios" + wakelock: + :path: ".symlinks/plugins/wakelock/ios" SPEC CHECKSUMS: Firebase: 44dd9724c84df18b486639e874f31436eaa9a20c @@ -71,6 +76,7 @@ SPEC CHECKSUMS: PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff + wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f PODFILE CHECKSUM: 56099e53bf102df458f588dbe78632cd13d5357b diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart index 48c36af8..eebfc4f4 100644 --- a/lib/generated_plugin_registrant.dart +++ b/lib/generated_plugin_registrant.dart @@ -9,6 +9,7 @@ import 'package:firebase_core_web/firebase_core_web.dart'; import 'package:url_launcher_web/url_launcher_web.dart'; import 'package:video_player_web/video_player_web.dart'; import 'package:video_player_web_hls/video_player_web_hls.dart'; +import 'package:wakelock_web/wakelock_web.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; @@ -18,5 +19,6 @@ void registerPlugins(Registrar registrar) { UrlLauncherPlugin.registerWith(registrar); VideoPlayerPlugin.registerWith(registrar); VideoPlayerPluginHls.registerWith(registrar); + WakelockWeb.registerWith(registrar); registrar.registerMessageHandler(); } diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index c03817f0..173468bf 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -1,7 +1,8 @@ import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; -import 'package:acela/src/widgets/controls_overlay.dart'; +// import 'package:acela/src/widgets/controls_overlay.dart'; +import 'package:chewie/chewie.dart'; class SPKVideoPlayer extends StatefulWidget { const SPKVideoPlayer( @@ -16,7 +17,10 @@ class SPKVideoPlayer extends StatefulWidget { class _SPKVideoPlayerState extends State with AutomaticKeepAliveClientMixin { - late VideoPlayerController controller; + // late VideoPlayerController controller; + + late VideoPlayerController videoPlayerController; + ChewieController? chewieController; @override bool get wantKeepAlive => true; @@ -24,16 +28,20 @@ class _SPKVideoPlayerState extends State @override void dispose() { super.dispose(); - controller.dispose(); + videoPlayerController.dispose(); } @override void initState() { - controller = VideoPlayerController.network(widget.playUrl, + videoPlayerController = VideoPlayerController.network(widget.playUrl, videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true)) ..initialize().then((_) { setState(() { - controller.play(); + chewieController = ChewieController( + videoPlayerController: videoPlayerController, + autoPlay: true, + looping: false, + ); }); }); super.initState(); @@ -42,30 +50,33 @@ class _SPKVideoPlayerState extends State @override Widget build(BuildContext context) { super.build(context); - return Center( - child: controller.value.isInitialized - ? AspectRatio( - aspectRatio: controller.value.aspectRatio, - child: Stack( - alignment: Alignment.bottomCenter, - children: [ - VideoPlayer(controller), - ClosedCaption(text: controller.value.caption.text), - ControlsOverlay( - controller: controller, - handleFullScreen: (value) { - widget.handleFullScreen(value); - }, - ), - VideoProgressIndicator( - controller, - allowScrubbing: true, - padding: const EdgeInsets.all(20), - ), - ], - ), - ) - : const LoadingScreen(), + return chewieController == null ? const LoadingScreen() : Chewie( + controller: chewieController!, ); + // return Center( + // child: controller.value.isInitialized + // ? AspectRatio( + // aspectRatio: controller.value.aspectRatio, + // child: Stack( + // alignment: Alignment.bottomCenter, + // children: [ + // VideoPlayer(controller), + // ClosedCaption(text: controller.value.caption.text), + // ControlsOverlay( + // controller: controller, + // handleFullScreen: (value) { + // widget.handleFullScreen(value); + // }, + // ), + // VideoProgressIndicator( + // controller, + // allowScrubbing: true, + // padding: const EdgeInsets.all(20), + // ), + // ], + // ), + // ) + // : const LoadingScreen(), + // ); } } diff --git a/pubspec.lock b/pubspec.lock index 9258f6bc..e3100621 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -113,6 +113,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + chewie: + dependency: "direct main" + description: + name: chewie + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" cli_util: dependency: transitive description: @@ -162,6 +169,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.17.1" + cupertino_icons: + dependency: transitive + description: + name: cupertino_icons + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" dart_style: dependency: transitive description: @@ -176,6 +190,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.2" file: dependency: transitive description: @@ -366,6 +387,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + nested: + dependency: transitive + description: + name: nested + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" package_config: dependency: transitive description: @@ -394,6 +422,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.5.0" + provider: + dependency: transitive + description: + name: provider + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.2" pub_semver: dependency: transitive description: @@ -574,6 +609,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.1" + very_good_analysis: + dependency: transitive + description: + name: very_good_analysis + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.0" video_player: dependency: "direct main" description: @@ -616,6 +658,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.11+4" + wakelock: + dependency: transitive + description: + name: wakelock + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.1+1" + wakelock_macos: + dependency: transitive + description: + name: wakelock_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.0" + wakelock_platform_interface: + dependency: transitive + description: + name: wakelock_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" + wakelock_web: + dependency: transitive + description: + name: wakelock_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.0" + wakelock_windows: + dependency: transitive + description: + name: wakelock_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" watcher: dependency: transitive description: @@ -630,6 +707,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + win32: + dependency: transitive + description: + name: win32 + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.1" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index dba1f345..1914332c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,6 +27,7 @@ environment: # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: + chewie: ^1.3.0 firebase_core: ^1.12.0 flutter: sdk: flutter From ef63268a3ecd1cd64653743155197427114d07e8 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 23 Feb 2022 06:31:48 +0530 Subject: [PATCH 033/466] =?UTF-8?q?1.=20replace=20the=20stack=20&=20show?= =?UTF-8?q?=20the=20feed=20-=20=E2=9C=85=202.=20chewie=20player=20done.=20?= =?UTF-8?q?=E2=9C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .firebase/hosting.YnVpbGQvd2Vi.cache | 30 +++++++++-------- .flutter-plugins-dependencies | 2 +- .idea/libraries/Flutter_Plugins.xml | 12 +++---- .packages | 2 +- lib/main.dart | 6 ++-- .../screens/drawer_screen/drawer_screen.dart | 7 ++-- lib/src/widgets/video_player.dart | 33 ++----------------- pubspec.yaml | 3 +- 8 files changed, 36 insertions(+), 59 deletions(-) diff --git a/.firebase/hosting.YnVpbGQvd2Vi.cache b/.firebase/hosting.YnVpbGQvd2Vi.cache index 666b2255..58f3bf4a 100644 --- a/.firebase/hosting.YnVpbGQvd2Vi.cache +++ b/.firebase/hosting.YnVpbGQvd2Vi.cache @@ -1,20 +1,22 @@ +favicon.png,1644471577919,a9fd35ee7a0d03fa369740142b0eadc6d794c7d94a3112a7d8fa5e1b9b00fe3f manifest.json,1643216912520,3b0da3b3b92dc0328b324ad0ad828f08f0d6807cb949b36f0ec722861759aacb assets/assets/branding/three_speak_icon.png,1643216912507,2d8407594c7d199c572113bc3de8a90d268d7b791a86573ee237ca1af71148ca assets/assets/branding/three_speak_logo.png,1643216912507,3ac2dbaa31235a5df9a7b984903728f8d524eebcaedc9e9312fe69cc569b3700 -assets/fonts/MaterialIcons-Regular.otf,1615596762000,5f71a8843e4edc9656c39061c2232458a6fc77e1603305960e4efa9c77f8b7a2 -version.json,1644912965037,0a47060cfa5ce3c6a31fc65b7b255084deb121b4698df6016d27e58cb5cd20fc -assets/FontManifest.json,1644912965144,2a26cf55926df210ccb9d713372cb114e0a12bf97104f6833e382566e2e7b16e -favicon.png,1644471577919,a9fd35ee7a0d03fa369740142b0eadc6d794c7d94a3112a7d8fa5e1b9b00fe3f -flutter_service_worker.js,1644912965581,92a01f3f606088166a39ffae1b8f2d5d7b2a88cfd17f3ccfd004e55950579c8f -assets/AssetManifest.json,1644912965143,0b95630463cd2782488987ad923759f47cc68f73214c391ade6944d7a27c7560 -index.html,1644912965149,102d98cdc2bb54dab279019ca3cafe97eb41fb6dacdc96c32bd0002bf0e011d0 -icons/Icon-192.png,1644471577919,4513a7b0bac37d1b6677f27b87f25c5f6f2dbcdad12ef49f43c1173788edd56d -icons/Icon-maskable-192.png,1644471577920,3a402c33b814408a1d4e91f1e7afab7b85b76247bc9fd735eb2007273008f5c6 canvaskit/canvaskit.js,315426600000,7070e00e23224440ff6333c831f4be11b9afd2d2b87b01753e524d4e8607edc8 -icons/Icon-512.png,1644471577920,1e65fd7dc5ed1eaab6aae9fd5a18542a1ee5baabd0f52c094c62f3595aa00af5 -icons/Icon-maskable-512.png,1644471577922,1a3f03a5d284c1bea6032c4bd42cc29f66504ada5351e1b161d8626af2f02c33 -canvaskit/profiling/canvaskit.js,315426600000,b64ecd48dbca34be0be9dceb61bd8a38dd24518ac0a70c4133553f9821bd0342 -assets/NOTICES,1644912965144,c1ca890cf2497ad99773292837197c505ca33416e4d06dc7b5ae83ad22dd11b5 -main.dart.js,1644912964550,7e4ca48c2670fa3d2e0534eeb8fc8ad5bc590a8c446c7eb739d2c853f01e84a0 canvaskit/canvaskit.wasm,315426600000,20ad62ae701d503e645f826e0f28863b020ba8f3568a04dbfe349e52f2bb1f06 +canvaskit/profiling/canvaskit.js,315426600000,b64ecd48dbca34be0be9dceb61bd8a38dd24518ac0a70c4133553f9821bd0342 canvaskit/profiling/canvaskit.wasm,315426600000,ae7385e32fe98cf31518919c377acc52a982a09758ef05fa5ec9c8bf069122ae +icons/Icon-192.png,1644471577919,4513a7b0bac37d1b6677f27b87f25c5f6f2dbcdad12ef49f43c1173788edd56d +icons/Icon-512.png,1644471577920,1e65fd7dc5ed1eaab6aae9fd5a18542a1ee5baabd0f52c094c62f3595aa00af5 +icons/Icon-maskable-192.png,1644471577920,3a402c33b814408a1d4e91f1e7afab7b85b76247bc9fd735eb2007273008f5c6 +icons/Icon-maskable-512.png,1644471577922,1a3f03a5d284c1bea6032c4bd42cc29f66504ada5351e1b161d8626af2f02c33 +version.json,1645575007984,0a47060cfa5ce3c6a31fc65b7b255084deb121b4698df6016d27e58cb5cd20fc +index.html,1645575008110,dff4af084a2506b035e647803e03e26b608f15d4c7809cd33551720d3b615142 +flutter_service_worker.js,1645575008554,a1fade752cbd84762f9c108c4203b61a64e57b4a003af1aa5cbacaa37c4462f2 +assets/AssetManifest.json,1645575008103,5fc8f0a4cb6a5fe5e0ac338d180bccd4504edee206418c30a4a2c89f28ba8567 +assets/packages/wakelock_web/assets/no_sleep.js,1643552921885,f21ecad86108032c97fe6d07e50f6d35bc4969aa3b2a005efae256ffe62f47e9 +assets/FontManifest.json,1645575008104,9ea504185602e57d97b7c3517d382b8627a13c0181c490c96a9b55a5d5c8810c +assets/packages/cupertino_icons/assets/CupertinoIcons.ttf,1639683241000,3064af137aeffc9011ba060601a01177b279963822310a778aeafa74c209732c +assets/NOTICES,1645575008104,d759bcc0ca6eeb13acc3a8424a11b50e35ca1c6381f6d1152590dc20511d04a7 +assets/fonts/MaterialIcons-Regular.otf,1639015896000,b9e3a9c3ffab1f1c8adbb4f67484ef1f2c4b50d318dc037d7d8f77c8e044c51c +main.dart.js,1645575007471,e1c5a1b03d5424fc3f15c0ff620f09cd6ecdf725430e7a6016f8a8a29885031c diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index a6237fd2..c9cb6607 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-02-22 16:41:53.269657","version":"2.10.2"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-02-23 06:30:58.625809","version":"2.10.2"} \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index a00db83c..f486e394 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -3,11 +3,6 @@ - - - - - @@ -15,9 +10,14 @@ - + + + + + + diff --git a/.packages b/.packages index 2b0999dd..5ca5fa90 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-02-22 16:17:43.777581. +# Generated by pub on 2022-02-23 06:30:58.357279. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-34.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.2.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ diff --git a/lib/main.dart b/lib/main.dart index b5ed1731..c1ab30cb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -74,13 +74,13 @@ class _MyAppState extends State { 'Home', "${server.domain}/apiv2/feeds/home", true); } else if (settings.name == "/trending") { return configuredHomeWidget( - 'Trending Content', "${server.domain}/apiv2/feeds/trending", false); + 'Trending Content', "${server.domain}/apiv2/feeds/trending", true); } else if (settings.name == "/new") { return configuredHomeWidget( - 'New Content', "${server.domain}/apiv2/feeds/new", false); + 'New Content', "${server.domain}/apiv2/feeds/new", true); } else if (settings.name == "/firstUploads") { return configuredHomeWidget( - 'First Uploads', "${server.domain}/apiv2/feeds/firstUploads", false); + 'First Uploads', "${server.domain}/apiv2/feeds/firstUploads", true); } else if (settings.name?.contains("/userChannel/") == true) { var last = settings.name?.split("/userChannel/").last ?? "sagarkothari88"; return configuredHomeWidget( diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index a871d0d2..ad4d2afc 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -14,6 +14,7 @@ class DrawerScreen extends StatelessWidget { title: const Text("Home"), onTap: () { Navigator.pop(context); + Navigator.of(context).pushReplacementNamed("/"); }, ); } @@ -24,7 +25,7 @@ class DrawerScreen extends StatelessWidget { title: const Text("First Uploads"), onTap: () { Navigator.pop(context); - Navigator.of(context).pushNamed("/firstUploads"); + Navigator.of(context).pushReplacementNamed("/firstUploads"); }, ); } @@ -35,7 +36,7 @@ class DrawerScreen extends StatelessWidget { title: const Text("Trending Content"), onTap: () { Navigator.pop(context); - Navigator.of(context).pushNamed("/trending"); + Navigator.of(context).pushReplacementNamed("/trending"); }, ); } @@ -46,7 +47,7 @@ class DrawerScreen extends StatelessWidget { title: const Text("New Content"), onTap: () { Navigator.pop(context); - Navigator.of(context).pushNamed("/new"); + Navigator.of(context).pushReplacementNamed("/new"); }, ); } diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index 173468bf..bb25e037 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -1,7 +1,6 @@ import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; -// import 'package:acela/src/widgets/controls_overlay.dart'; import 'package:chewie/chewie.dart'; class SPKVideoPlayer extends StatefulWidget { @@ -17,7 +16,6 @@ class SPKVideoPlayer extends StatefulWidget { class _SPKVideoPlayerState extends State with AutomaticKeepAliveClientMixin { - // late VideoPlayerController controller; late VideoPlayerController videoPlayerController; ChewieController? chewieController; @@ -50,33 +48,8 @@ class _SPKVideoPlayerState extends State @override Widget build(BuildContext context) { super.build(context); - return chewieController == null ? const LoadingScreen() : Chewie( - controller: chewieController!, - ); - // return Center( - // child: controller.value.isInitialized - // ? AspectRatio( - // aspectRatio: controller.value.aspectRatio, - // child: Stack( - // alignment: Alignment.bottomCenter, - // children: [ - // VideoPlayer(controller), - // ClosedCaption(text: controller.value.caption.text), - // ControlsOverlay( - // controller: controller, - // handleFullScreen: (value) { - // widget.handleFullScreen(value); - // }, - // ), - // VideoProgressIndicator( - // controller, - // allowScrubbing: true, - // padding: const EdgeInsets.all(20), - // ), - // ], - // ), - // ) - // : const LoadingScreen(), - // ); + return chewieController == null + ? const LoadingScreen() + : Chewie(controller: chewieController!); } } diff --git a/pubspec.yaml b/pubspec.yaml index 1914332c..5341c877 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 +version: 1.0.0+2 environment: sdk: ">=2.15.1 <3.0.0" @@ -28,6 +28,7 @@ environment: # versions available, run `flutter pub outdated`. dependencies: chewie: ^1.3.0 +# better_player: ^0.0.81 firebase_core: ^1.12.0 flutter: sdk: flutter From 7dd1d638ac17d946f59805a02fe878cecc94844b Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 23 Feb 2022 08:29:13 +0530 Subject: [PATCH 034/466] =?UTF-8?q?8.=20share=20this=20video=20on=20video?= =?UTF-8?q?=20details=20page=20=20=E2=9C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .flutter-plugins | 3 ++ .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 48 ++++++++++++++++++ .idea/libraries/Flutter_Plugins.xml | 19 ++++--- .packages | 8 ++- lib/generated_plugin_registrant.dart | 2 + .../user_channel_screen.dart | 15 ++++++ .../video_details_screen.dart | 5 +- .../video_details_tabbed_widget.dart | 49 +++++++++++++------ pubspec.lock | 42 ++++++++++++++++ pubspec.yaml | 2 +- 11 files changed, 169 insertions(+), 26 deletions(-) create mode 100644 lib/src/screens/user_channel_screen/user_channel_screen.dart diff --git a/.flutter-plugins b/.flutter-plugins index 66c8c031..612fe620 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,6 +1,9 @@ # This is a generated file; do not edit or check into version control. firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/ firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/ +share_plus=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/ +share_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/ +share_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/ url_launcher=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.20/ url_launcher_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/ url_launcher_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index c9cb6607..4c29f778 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-02-23 06:30:58.625809","version":"2.10.2"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-02-23 08:19:32.997890","version":"2.10.2"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index d7710845..ee9d094b 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -450,6 +450,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -794,6 +836,12 @@ + + + + + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index f486e394..e41217bd 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,23 +1,26 @@ - + + + + + - - - + - - - - + + + + + diff --git a/.packages b/.packages index 5ca5fa90..14f9a630 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-02-23 06:30:58.357279. +# Generated by pub on 2022-02-23 08:13:21.030953. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-34.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.2.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ @@ -68,6 +68,12 @@ pool:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/poo provider:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/provider-6.0.2/lib/ pub_semver:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pub_semver-2.1.0/lib/ pubspec_parse:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pubspec_parse-1.2.0/lib/ +share_plus:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/lib/ +share_plus_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-2.0.4/lib/ +share_plus_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/lib/ +share_plus_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_platform_interface-2.0.1/lib/ +share_plus_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/lib/ +share_plus_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-2.0.3/lib/ shelf:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.2.0/lib/ shelf_web_socket:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-1.0.1/lib/ sky_engine:file:///Applications/flutter/flutter/bin/cache/pkg/sky_engine/lib/ diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart index eebfc4f4..f054dcde 100644 --- a/lib/generated_plugin_registrant.dart +++ b/lib/generated_plugin_registrant.dart @@ -6,6 +6,7 @@ // ignore_for_file: lines_longer_than_80_chars import 'package:firebase_core_web/firebase_core_web.dart'; +import 'package:share_plus_web/share_plus_web.dart'; import 'package:url_launcher_web/url_launcher_web.dart'; import 'package:video_player_web/video_player_web.dart'; import 'package:video_player_web_hls/video_player_web_hls.dart'; @@ -16,6 +17,7 @@ import 'package:flutter_web_plugins/flutter_web_plugins.dart'; // ignore: public_member_api_docs void registerPlugins(Registrar registrar) { FirebaseCoreWeb.registerWith(registrar); + SharePlusPlugin.registerWith(registrar); UrlLauncherPlugin.registerWith(registrar); VideoPlayerPlugin.registerWith(registrar); VideoPlayerPluginHls.registerWith(registrar); diff --git a/lib/src/screens/user_channel_screen/user_channel_screen.dart b/lib/src/screens/user_channel_screen/user_channel_screen.dart new file mode 100644 index 00000000..a282c8b3 --- /dev/null +++ b/lib/src/screens/user_channel_screen/user_channel_screen.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class UserChannelScreen extends StatefulWidget { + const UserChannelScreen({Key? key}) : super(key: key); + + @override + _UserChannelScreenState createState() => _UserChannelScreenState(); +} + +class _UserChannelScreenState extends State { + @override + Widget build(BuildContext context) { + return Container(); + } +} diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 143b5629..b36992bd 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -1,3 +1,4 @@ +import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; import 'package:acela/src/screens/video_details_screen/video_details_recommendation.dart'; @@ -91,7 +92,9 @@ class _VideoDetailsScreenState extends State { children: tabBarChildren(data), title: data.title, onUserTap: onUserTap, - fullscreen: fullscreen, + fullscreen: fullscreen, + routeName: + "${server.domain}${VideoDetailsScreen.routeName(data.owner, data.permlink)}", ); } else { return container( diff --git a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart index 9c2deb5a..cea42692 100644 --- a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart +++ b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart @@ -1,17 +1,21 @@ import 'package:flutter/material.dart'; +import 'dart:io' show Platform; +import 'package:share_plus/share_plus.dart'; class VideoDetailsTabbedWidget extends StatefulWidget { - const VideoDetailsTabbedWidget({ - Key? key, - required this.children, - required this.title, - required this.onUserTap, - required this.fullscreen, - }) : super(key: key); + const VideoDetailsTabbedWidget( + {Key? key, + required this.children, + required this.title, + required this.onUserTap, + required this.fullscreen, + required this.routeName}) + : super(key: key); final List children; final String title; final Function onUserTap; final bool fullscreen; + final String routeName; @override _VideoDetailsTabbedWidgetState createState() => @@ -41,6 +45,29 @@ class _VideoDetailsTabbedWidgetState extends State super.dispose(); } + List _buttons() { + var channelButton = IconButton( + onPressed: () { + widget.onUserTap(); + }, + icon: const Icon(Icons.person), + ); + var shareButton = IconButton( + onPressed: () { + Share.share( + widget.routeName, + subject: 'I found this video interesting ${widget.routeName}', + ); + }, + icon: const Icon(Icons.share), + ); + if (Platform.isAndroid || Platform.isIOS) { + return [channelButton, shareButton]; + } else { + return [channelButton]; + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -48,13 +75,7 @@ class _VideoDetailsTabbedWidgetState extends State ? null : AppBar( title: Text(widget.title), - actions: [ - IconButton( - onPressed: () { - widget.onUserTap(); - }, - icon: const Icon(Icons.person)), - ], + actions: _buttons(), bottom: TabBar( controller: _tabController, isScrollable: true, diff --git a/pubspec.lock b/pubspec.lock index e3100621..dfef7056 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -443,6 +443,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + share_plus: + dependency: "direct main" + description: + name: share_plus + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + share_plus_linux: + dependency: transitive + description: + name: share_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + share_plus_macos: + dependency: transitive + description: + name: share_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + share_plus_web: + dependency: transitive + description: + name: share_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + share_plus_windows: + dependency: transitive + description: + name: share_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5341c877..bfff74bb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,13 +28,13 @@ environment: # versions available, run `flutter pub outdated`. dependencies: chewie: ^1.3.0 -# better_player: ^0.0.81 firebase_core: ^1.12.0 flutter: sdk: flutter flutter_markdown: ^0.6.9 http: ^0.13.4 json_annotation: ^4.4.0 + share_plus: ^3.1.0 timeago: ^3.1.0 url_launcher: ^6.0.20 video_player: ^2.2.14 From a1e5d50a3065d0dc686cfe0a7120f859aeb18f22 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 23 Feb 2022 11:24:03 +0530 Subject: [PATCH 035/466] details in progress. --- .flutter-plugins-dependencies | 2 +- .idea/misc.xml | 3 + lib/main.dart | 6 +- .../request/user_profile_request.dart | 62 ++++++ .../user_profile/response/user_profile.dart | 176 ++++++++++++++++++ .../user_channel_screen.dart | 163 +++++++++++++++- 6 files changed, 407 insertions(+), 5 deletions(-) create mode 100644 lib/src/models/user_profile/request/user_profile_request.dart create mode 100644 lib/src/models/user_profile/response/user_profile.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 4c29f778..c3f90dde 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-02-23 08:19:32.997890","version":"2.10.2"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-02-23 11:18:59.711110","version":"2.10.2"} \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index f4f6d798..6e5825fe 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,6 +3,9 @@ + + + diff --git a/lib/main.dart b/lib/main.dart index c1ab30cb..20916b92 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:acela/src/screens/communities_screen/communities_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:firebase_core/firebase_core.dart'; @@ -83,8 +84,9 @@ class _MyAppState extends State { 'First Uploads', "${server.domain}/apiv2/feeds/firstUploads", true); } else if (settings.name?.contains("/userChannel/") == true) { var last = settings.name?.split("/userChannel/").last ?? "sagarkothari88"; - return configuredHomeWidget( - last, "${server.domain}/apiv2/feeds/@$last", false); + return MaterialPageRoute(builder: (context) { + return UserChannelScreen(owner: last); + }); } else if (settings.name == "/leaderboard") { return MaterialPageRoute(builder: (context) { return const LeaderboardScreen(); diff --git a/lib/src/models/user_profile/request/user_profile_request.dart b/lib/src/models/user_profile/request/user_profile_request.dart new file mode 100644 index 00000000..39e270ff --- /dev/null +++ b/lib/src/models/user_profile/request/user_profile_request.dart @@ -0,0 +1,62 @@ +import 'dart:convert'; +import 'package:acela/src/utils/safe_convert.dart'; + +class UserProfileRequest { + // 2.0 + final String jsonrpc; + + // bridge.get_profile + final String method; + final UserProfileRequestParams params; + + // 1 + final int id; + + UserProfileRequest({ + this.jsonrpc = "", + this.method = "", + required this.params, + this.id = 0, + }); + + factory UserProfileRequest.fromJson(Map? json) => + UserProfileRequest( + jsonrpc: asString(json, 'jsonrpc'), + method: asString(json, 'method'), + params: UserProfileRequestParams.fromJson(asMap(json, 'params')), + id: asInt(json, 'id'), + ); + + factory UserProfileRequest.forOwner(String owner) => UserProfileRequest( + jsonrpc: "2.0", + method: "bridge.get_profile", + params: UserProfileRequestParams(account: owner), + id: 1); + + Map toJson() => { + 'jsonrpc': jsonrpc, + 'method': method, + 'params': params.toJson(), + 'id': id, + }; + + String toJsonString() => json.encode(toJson()); +} + +class UserProfileRequestParams { + // sagarkothari88 + final String account; + + UserProfileRequestParams({ + this.account = "", + }); + + factory UserProfileRequestParams.fromJson(Map? json) => + UserProfileRequestParams( + account: asString(json, 'account'), + ); + + Map toJson() => { + 'account': account, + }; +} diff --git a/lib/src/models/user_profile/response/user_profile.dart b/lib/src/models/user_profile/response/user_profile.dart new file mode 100644 index 00000000..6148a52d --- /dev/null +++ b/lib/src/models/user_profile/response/user_profile.dart @@ -0,0 +1,176 @@ +import 'dart:convert'; +import 'package:acela/src/utils/safe_convert.dart'; + +class UserProfileResponse { + // 2.0 + final String jsonrpc; + final UserProfile result; + // 1 + final int id; + + UserProfileResponse({ + this.jsonrpc = "", + required this.result, + this.id = 0, + }); + + factory UserProfileResponse.fromJson(Map? json) => UserProfileResponse( + jsonrpc: asString(json, 'jsonrpc'), + result: UserProfile.fromJson(asMap(json, 'result')), + id: asInt(json, 'id'), + ); + + factory UserProfileResponse.fromString(String string) { + return UserProfileResponse.fromJson(json.decode(string)); + } + + Map toJson() => { + 'jsonrpc': jsonrpc, + 'result': result.toJson(), + 'id': id, + }; +} + +class UserProfile { + // 2267004 + final int id; + // sagarkothari88 + final String name; + // 2021-11-18T17:43:36 + final String created; + // 2022-02-23T00:27:15 + final String active; + // 82 + final int postCount; + // 61.36 + final double reputation; + final UserProfileStats stats; + final UserProfileMetadata metadata; + + UserProfile({ + this.id = 0, + this.name = "", + this.created = "", + this.active = "", + this.postCount = 0, + this.reputation = 0.0, + required this.stats, + required this.metadata, + }); + + factory UserProfile.fromJson(Map? json) => UserProfile( + id: asInt(json, 'id'), + name: asString(json, 'name'), + created: asString(json, 'created'), + active: asString(json, 'active'), + postCount: asInt(json, 'post_count'), + reputation: asDouble(json, 'reputation'), + stats: UserProfileStats.fromJson(asMap(json, 'stats')), + metadata: UserProfileMetadata.fromJson(asMap(json, 'metadata')), + ); + + Map toJson() => { + 'id': id, + 'name': name, + 'created': created, + 'active': active, + 'post_count': postCount, + 'reputation': reputation, + 'stats': stats.toJson(), + 'metadata': metadata.toJson(), + }; +} + +class UserProfileStats { + // 0 + final int rank; + // 9 + final int following; + // 18 + final int followers; + + UserProfileStats({ + this.rank = 0, + this.following = 0, + this.followers = 0, + }); + + factory UserProfileStats.fromJson(Map? json) => UserProfileStats( + rank: asInt(json, 'rank'), + following: asInt(json, 'following'), + followers: asInt(json, 'followers'), + ); + + Map toJson() => { + 'rank': rank, + 'following': following, + 'followers': followers, + }; +} + + +class UserProfileMetadata { + final UserProfileMetadataProfile profile; + + UserProfileMetadata({ + required this.profile, + }); + + factory UserProfileMetadata.fromJson(Map? json) => UserProfileMetadata( + profile: UserProfileMetadataProfile.fromJson(asMap(json, 'profile')), + ); + + Map toJson() => { + 'profile': profile.toJson(), + }; +} + +class UserProfileMetadataProfile { + // sagar.kothari.88 + final String name; + // Block chain based Social Media - Mobile App Developer + final String about; + final String website; + // On Internet + final String location; + // https://files.peakd.com/file/peakd-hive/sagarkothari88/sagar.kothari.png + final String coverImage; + // https://files.peakd.com/file/peakd-hive/sagarkothari88/None_32e767de-b206-4f60-a4ca-b22f51f29d8c.jpg + final String profileImage; + final String blacklistDescription; + final String mutedListDescription; + + UserProfileMetadataProfile({ + this.name = "", + this.about = "", + this.website = "", + this.location = "", + this.coverImage = "", + this.profileImage = "", + this.blacklistDescription = "", + this.mutedListDescription = "", + }); + + factory UserProfileMetadataProfile.fromJson(Map? json) => UserProfileMetadataProfile( + name: asString(json, 'name'), + about: asString(json, 'about'), + website: asString(json, 'website'), + location: asString(json, 'location'), + coverImage: asString(json, 'cover_image'), + profileImage: asString(json, 'profile_image'), + blacklistDescription: asString(json, 'blacklist_description'), + mutedListDescription: asString(json, 'muted_list_description'), + ); + + Map toJson() => { + 'name': name, + 'about': about, + 'website': website, + 'location': location, + 'cover_image': coverImage, + 'profile_image': profileImage, + 'blacklist_description': blacklistDescription, + 'muted_list_description': mutedListDescription, + }; +} + diff --git a/lib/src/screens/user_channel_screen/user_channel_screen.dart b/lib/src/screens/user_channel_screen/user_channel_screen.dart index a282c8b3..2bb03521 100644 --- a/lib/src/screens/user_channel_screen/user_channel_screen.dart +++ b/lib/src/screens/user_channel_screen/user_channel_screen.dart @@ -1,15 +1,174 @@ +import 'dart:developer'; + +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/models/user_profile/request/user_profile_request.dart'; +import 'package:acela/src/models/user_profile/response/user_profile.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; +import 'package:acela/src/utils/seconds_to_duration.dart'; +import 'package:acela/src/widgets/custom_circle_avatar.dart'; +import 'package:acela/src/widgets/list_tile_video.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:http/http.dart' show get; +import 'package:timeago/timeago.dart' as timeago; class UserChannelScreen extends StatefulWidget { - const UserChannelScreen({Key? key}) : super(key: key); + const UserChannelScreen({Key? key, required this.owner}) : super(key: key); + final String owner; @override _UserChannelScreenState createState() => _UserChannelScreenState(); } class _UserChannelScreenState extends State { + List items = []; + + Future loadUserProfile(String author) async { + var client = http.Client(); + var body = UserProfileRequest.forOwner(widget.owner).toJsonString(); + var response = await client.post(Uri.parse(server.hiveDomain), body: body); + if (response.statusCode == 200) { + _loadFeed(); + return UserProfileResponse.fromString(response.body); + } else { + throw "Status code is ${response.statusCode}"; + } + } + + void _loadFeed() { + get(Uri.parse("${server.domain}/apiv2/feeds/@${widget.owner}")) + .then((value) { + if (value.statusCode == 200) { + List list = homeFeedItemFromString(value.body); + setState(() { + items = list; + }); + } + }); + } + + Widget _tileTitle(HomeFeedItem item, BuildContext context, + Function(HomeFeedItem) onUserTap) { + String timeInString = + item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; + String owner = "👤 ${item.author}"; + String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; + String views = "▶ ${item.views}"; + return ListTileVideo( + placeholder: 'assets/branding/three_speak_logo.png', + url: item.images.thumbnail, + userThumbUrl: server.userOwnerThumb(item.author), + title: item.title, + subtitle: "$timeInString $owner $duration $views", + onUserTap: () { + onUserTap(item); + }, + ); + } + + Widget _listTile(HomeFeedItem item, BuildContext context, + Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { + return ListTile( + title: _tileTitle(item, context, onUserTap), + onTap: () { + onTap(item); + }, + ); + } + + Widget _cover(String url) { + return FadeInImage.assetNetwork( + height: 150, + placeholder: 'assets/branding/three_speak_logo.png', + image: url, + //data.result.metadata.profile.coverImage, + fit: BoxFit.cover, + imageErrorBuilder: + (BuildContext context, Object error, StackTrace? stackTrace) { + return Image.asset('assets/branding/three_speak_logo.png'); + }, + ); + } + + Widget _thumbnail(String url, String name) { + return Container( + padding: const EdgeInsets.all(10), + child: Row( + children: [ + CustomCircleAvatar( + height: 100, + width: 100, + url: url), //data.result.metadata.profile.profileImage), + const SizedBox( + width: 10, + ), + Text( + name, + style: Theme.of(context).textTheme.displaySmall, + ), + ], + ), + ); + } + + Widget _bio(String bio) { + return Container( + padding: const EdgeInsets.all(10), + child: Expanded(child: Text(bio)), + ); + } + + Widget _userProfile(UserProfileResponse data) { + return ListView.separated( + itemBuilder: (context, index) { + if (index == 0) { + return _cover(data.result.metadata.profile.coverImage); + } else if (index == 1) { + return _thumbnail( + data.result.metadata.profile.profileImage, data.result.name); + } else if (index == 2) { + return _bio(data.result.metadata.profile.about); + } else { + return _listTile(items[index - 3], context, (item) { + log("tapped on item ${item.permlink}"); + Navigator.of(context).pushNamed( + VideoDetailsScreen.routeName(item.author, item.permlink)); + }, (owner) { + log("tapped on user ${owner.author}"); + }); + } + }, + separatorBuilder: (context, index) => + const Divider(thickness: 0, height: 1, color: Colors.transparent), + itemCount: items.length + 3, + ); + } + + Widget _futureBuilder() { + return FutureBuilder( + future: loadUserProfile(widget.owner), + builder: (context, snapshot) { + if (snapshot.hasError) { + return const Text('Firebase not initialized'); + } else if (snapshot.hasData) { + var data = snapshot.data! as UserProfileResponse; + return _userProfile(data); + } else { + return const LoadingScreen(); + } + }, + ); + } + @override Widget build(BuildContext context) { - return Container(); + return Scaffold( + appBar: AppBar( + title: Text(widget.owner), + ), + body: _futureBuilder(), + ); } } From 1af9bd47aff9deb27459d95431c36d54058d065a Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 28 Feb 2022 17:31:47 +0530 Subject: [PATCH 036/466] Community details in progress. --- .firebase/hosting.YnVpbGQvd2Vi.cache | 20 +-- .flutter-plugins-dependencies | 2 +- ios/Podfile.lock | 6 + ios/Runner.xcodeproj/project.pbxproj | 6 +- ios/Runner/Info.plist | 2 +- lib/main.dart | 9 +- .../communities_screen.dart | 3 +- .../community_details_screen.dart | 123 ++++++++++++++++++ .../video_details_tabbed_widget.dart | 10 +- 9 files changed, 159 insertions(+), 22 deletions(-) create mode 100644 lib/src/screens/communities_screen/community_details/community_details_screen.dart diff --git a/.firebase/hosting.YnVpbGQvd2Vi.cache b/.firebase/hosting.YnVpbGQvd2Vi.cache index 58f3bf4a..bbb7ab54 100644 --- a/.firebase/hosting.YnVpbGQvd2Vi.cache +++ b/.firebase/hosting.YnVpbGQvd2Vi.cache @@ -2,6 +2,9 @@ favicon.png,1644471577919,a9fd35ee7a0d03fa369740142b0eadc6d794c7d94a3112a7d8fa5e manifest.json,1643216912520,3b0da3b3b92dc0328b324ad0ad828f08f0d6807cb949b36f0ec722861759aacb assets/assets/branding/three_speak_icon.png,1643216912507,2d8407594c7d199c572113bc3de8a90d268d7b791a86573ee237ca1af71148ca assets/assets/branding/three_speak_logo.png,1643216912507,3ac2dbaa31235a5df9a7b984903728f8d524eebcaedc9e9312fe69cc569b3700 +assets/fonts/MaterialIcons-Regular.otf,1639015896000,b9e3a9c3ffab1f1c8adbb4f67484ef1f2c4b50d318dc037d7d8f77c8e044c51c +assets/packages/cupertino_icons/assets/CupertinoIcons.ttf,1639683241000,3064af137aeffc9011ba060601a01177b279963822310a778aeafa74c209732c +assets/packages/wakelock_web/assets/no_sleep.js,1643552921885,f21ecad86108032c97fe6d07e50f6d35bc4969aa3b2a005efae256ffe62f47e9 canvaskit/canvaskit.js,315426600000,7070e00e23224440ff6333c831f4be11b9afd2d2b87b01753e524d4e8607edc8 canvaskit/canvaskit.wasm,315426600000,20ad62ae701d503e645f826e0f28863b020ba8f3568a04dbfe349e52f2bb1f06 canvaskit/profiling/canvaskit.js,315426600000,b64ecd48dbca34be0be9dceb61bd8a38dd24518ac0a70c4133553f9821bd0342 @@ -10,13 +13,10 @@ icons/Icon-192.png,1644471577919,4513a7b0bac37d1b6677f27b87f25c5f6f2dbcdad12ef49 icons/Icon-512.png,1644471577920,1e65fd7dc5ed1eaab6aae9fd5a18542a1ee5baabd0f52c094c62f3595aa00af5 icons/Icon-maskable-192.png,1644471577920,3a402c33b814408a1d4e91f1e7afab7b85b76247bc9fd735eb2007273008f5c6 icons/Icon-maskable-512.png,1644471577922,1a3f03a5d284c1bea6032c4bd42cc29f66504ada5351e1b161d8626af2f02c33 -version.json,1645575007984,0a47060cfa5ce3c6a31fc65b7b255084deb121b4698df6016d27e58cb5cd20fc -index.html,1645575008110,dff4af084a2506b035e647803e03e26b608f15d4c7809cd33551720d3b615142 -flutter_service_worker.js,1645575008554,a1fade752cbd84762f9c108c4203b61a64e57b4a003af1aa5cbacaa37c4462f2 -assets/AssetManifest.json,1645575008103,5fc8f0a4cb6a5fe5e0ac338d180bccd4504edee206418c30a4a2c89f28ba8567 -assets/packages/wakelock_web/assets/no_sleep.js,1643552921885,f21ecad86108032c97fe6d07e50f6d35bc4969aa3b2a005efae256ffe62f47e9 -assets/FontManifest.json,1645575008104,9ea504185602e57d97b7c3517d382b8627a13c0181c490c96a9b55a5d5c8810c -assets/packages/cupertino_icons/assets/CupertinoIcons.ttf,1639683241000,3064af137aeffc9011ba060601a01177b279963822310a778aeafa74c209732c -assets/NOTICES,1645575008104,d759bcc0ca6eeb13acc3a8424a11b50e35ca1c6381f6d1152590dc20511d04a7 -assets/fonts/MaterialIcons-Regular.otf,1639015896000,b9e3a9c3ffab1f1c8adbb4f67484ef1f2c4b50d318dc037d7d8f77c8e044c51c -main.dart.js,1645575007471,e1c5a1b03d5424fc3f15c0ff620f09cd6ecdf725430e7a6016f8a8a29885031c +version.json,1646043299272,595e9d230a7c822b2662ef5c26fb0570fbe5d8e087148c8c33e2c9b37812a7cd +index.html,1646043299424,cae048bb7a0f6dae11f34d40ed6d26e04ae0297b008e5aad4d23b159e9922fb8 +flutter_service_worker.js,1646043299788,96f1f84574b47e45b82f56840e85f6a586b43fb567309a58bcacd25521067add +assets/AssetManifest.json,1646043299412,5fc8f0a4cb6a5fe5e0ac338d180bccd4504edee206418c30a4a2c89f28ba8567 +assets/FontManifest.json,1646043299413,9ea504185602e57d97b7c3517d382b8627a13c0181c490c96a9b55a5d5c8810c +assets/NOTICES,1646043299413,9d7a8cc3894e8811e2b051e5c03582ed396c8785d66ee3cae6f5d2e0299e5929 +main.dart.js,1646043299003,35eb2c0caed7b451abb22e2676a79adff33f71937cf6ed32b71a6067a11f2b38 diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index c3f90dde..c60c4157 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-02-23 11:18:59.711110","version":"2.10.2"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-02-28 17:11:35.229355","version":"2.10.2"} \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ddb317c5..3a0cbbf2 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -28,6 +28,8 @@ PODS: - nanopb/decode (2.30908.0) - nanopb/encode (2.30908.0) - PromisesObjC (2.0.0) + - share_plus (0.0.1): + - Flutter - url_launcher_ios (0.0.1): - Flutter - video_player_avfoundation (0.0.1): @@ -38,6 +40,7 @@ PODS: DEPENDENCIES: - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - Flutter (from `Flutter`) + - share_plus (from `.symlinks/plugins/share_plus/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) - wakelock (from `.symlinks/plugins/wakelock/ios`) @@ -57,6 +60,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/firebase_core/ios" Flutter: :path: Flutter + share_plus: + :path: ".symlinks/plugins/share_plus/ios" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" video_player_avfoundation: @@ -74,6 +79,7 @@ SPEC CHECKSUMS: GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 + share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 65bc1088..2b8415a7 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -358,7 +358,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -487,7 +487,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -510,7 +510,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index cffa1ab8..74963471 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - $(FLUTTER_BUILD_NUMBER) + $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS NSAppTransportSecurity diff --git a/lib/main.dart b/lib/main.dart index 20916b92..ca931211 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:acela/src/screens/communities_screen/communities_screen.dart'; +import 'package:acela/src/screens/communities_screen/community_details/community_details_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; @@ -83,10 +84,16 @@ class _MyAppState extends State { return configuredHomeWidget( 'First Uploads', "${server.domain}/apiv2/feeds/firstUploads", true); } else if (settings.name?.contains("/userChannel/") == true) { - var last = settings.name?.split("/userChannel/").last ?? "sagarkothari88"; + var last = settings.name?.split("/userChannel/").last ?? "threespeak"; return MaterialPageRoute(builder: (context) { return UserChannelScreen(owner: last); }); + } else if (settings.name?.contains('/community/') == true) { + var last = settings.name?.split("/community/").last ?? "hive-167922?name=LeoFinance"; + var comps = last.split("?name="); + return MaterialPageRoute(builder: (context) { + return CommunityDetailScreen(name: comps[0], title: comps[1]); + }); } else if (settings.name == "/leaderboard") { return MaterialPageRoute(builder: (context) { return const LeaderboardScreen(); diff --git a/lib/src/screens/communities_screen/communities_screen.dart b/lib/src/screens/communities_screen/communities_screen.dart index a37cc4cb..780ff401 100644 --- a/lib/src/screens/communities_screen/communities_screen.dart +++ b/lib/src/screens/communities_screen/communities_screen.dart @@ -41,7 +41,8 @@ class _CommunitiesScreenState extends State { title: Text(item.title), subtitle: Text(item.about), onTap: () { - log("user tapped on ${item.name}"); + Navigator.of(context) + .pushNamed('/community/${item.name}?name=${item.title}'); }, ); } diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart new file mode 100644 index 00000000..c12f8919 --- /dev/null +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -0,0 +1,123 @@ +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; +import 'package:acela/src/utils/seconds_to_duration.dart'; +import 'package:acela/src/widgets/list_tile_video.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:acela/src/widgets/retry.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; +import 'package:timeago/timeago.dart' as timeago; + +class CommunityDetailScreen extends StatefulWidget { + const CommunityDetailScreen({Key? key, required this.name, required this.title}) : super(key: key); + final String name; + final String title; + + @override + _CommunityDetailScreenState createState() => _CommunityDetailScreenState(); +} + +class _CommunityDetailScreenState extends State { + late Future> _loadingFeed; + + Future> loadHomeFeed() async { + var uri = Uri.parse( + 'https://3speak.tv/apiv2/feeds/community/${widget.name}/new'); + var response = await get(uri); + if (response.statusCode == 200) { + List list = homeFeedItemFromString(response.body); + return list; + } else { + throw 'Status code ${response.statusCode}'; + } + } + + @override + void initState() { + super.initState(); + _loadingFeed = loadHomeFeed(); + } + + void onTap(HomeFeedItem item) { + Navigator.of(context) + .pushNamed(VideoDetailsScreen.routeName(item.author, item.permlink)); + } + + void onUserTap(HomeFeedItem item) { + Navigator.of(context).pushNamed("/userChannel/${item.author}"); + } + + Widget _tileTitle(HomeFeedItem item, BuildContext context, + Function(HomeFeedItem) onUserTap) { + String timeInString = + item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; + String owner = "👤 ${item.author}"; + String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; + String views = "▶ ${item.views}"; + return ListTileVideo( + placeholder: 'assets/branding/three_speak_logo.png', + url: item.images.thumbnail, + userThumbUrl: server.userOwnerThumb(item.author), + title: item.title, + subtitle: "$timeInString $owner $duration $views", + onUserTap: () { + onUserTap(item); + }, + ); + } + + Widget _listTile(HomeFeedItem item, BuildContext context, + Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { + return ListTile( + title: _tileTitle(item, context, onUserTap), + onTap: () { + onTap(item); + }, + ); + } + + Widget list(List list, Future Function() onRefresh, + Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { + return RefreshIndicator( + onRefresh: onRefresh, + child:ListView.separated( + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (context, index) { + return _listTile(list[index], context, onTap, onUserTap); + }, + separatorBuilder: (context, index) => const Divider( + thickness: 0, height: 1, color: Colors.transparent), + itemCount: list.length, + ) + ); + } + + Widget _screen() { + return FutureBuilder( + future: _loadingFeed, + builder: (builder, snapshot) { + if (snapshot.hasError) { + return RetryScreen( + error: snapshot.error?.toString() ?? 'Something went wrong', + onRetry: loadHomeFeed); + } else if (snapshot.hasData) { + List items = snapshot.data! as List; + return list(items, loadHomeFeed, onTap, onUserTap); + } else { + return const LoadingScreen(); + } + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: _screen(), + ); + } +} diff --git a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart index cea42692..05331fd5 100644 --- a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart +++ b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'dart:io' show Platform; +// import 'dart:io' show Platform; import 'package:share_plus/share_plus.dart'; class VideoDetailsTabbedWidget extends StatefulWidget { @@ -61,11 +61,11 @@ class _VideoDetailsTabbedWidgetState extends State }, icon: const Icon(Icons.share), ); - if (Platform.isAndroid || Platform.isIOS) { - return [channelButton, shareButton]; - } else { + // if (Platform.isAndroid || Platform.isIOS) { + // return [channelButton, shareButton]; + // } else { return [channelButton]; - } + // } } @override From c5c7fcb897b3a2f334ed3a38128393ab2a6c463e Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 2 Mar 2022 12:41:17 +0530 Subject: [PATCH 037/466] tabs in user-channel --- .flutter-plugins-dependencies | 2 +- .idea/modules.xml | 1 + acela.iml | 6 + android/acela_android.iml | 2 +- .../request/user_followers_request.dart | 50 +++++ .../response/followers_and_following.dart | 55 ++++++ .../user_channel_screen.dart | 175 +++++++++++------- lib/src/utils/seconds_to_duration.dart | 5 + 8 files changed, 223 insertions(+), 73 deletions(-) create mode 100644 lib/src/models/user_profile/request/user_followers_request.dart create mode 100644 lib/src/models/user_profile/response/followers_and_following.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index c60c4157..241fef56 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-02-28 17:11:35.229355","version":"2.10.2"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-02 05:55:01.376560","version":"2.10.2"} \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index bc717bbb..81617e7d 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -3,6 +3,7 @@ + \ No newline at end of file diff --git a/acela.iml b/acela.iml index 6d20190f..e6299203 100644 --- a/acela.iml +++ b/acela.iml @@ -72,6 +72,12 @@ + + + + + + diff --git a/android/acela_android.iml b/android/acela_android.iml index 18999696..3e44773e 100644 --- a/android/acela_android.iml +++ b/android/acela_android.iml @@ -26,4 +26,4 @@ - + \ No newline at end of file diff --git a/lib/src/models/user_profile/request/user_followers_request.dart b/lib/src/models/user_profile/request/user_followers_request.dart new file mode 100644 index 00000000..69797c5a --- /dev/null +++ b/lib/src/models/user_profile/request/user_followers_request.dart @@ -0,0 +1,50 @@ +import 'dart:convert'; +import 'package:acela/src/utils/safe_convert.dart'; + +class UserFollowerRequest { + // 2.0 + final String jsonrpc; + + // bridge.get_profile + final String method; + final List params; + + // 1 + final int id; + + UserFollowerRequest({ + this.jsonrpc = "", + this.method = "", + required this.params, + this.id = 0, + }); + + factory UserFollowerRequest.fromJson(Map? json) => + UserFollowerRequest( + jsonrpc: asString(json, 'jsonrpc'), + method: asString(json, 'method'), + params: asList(json, 'params').map((e) => e.toString()).toList(), + id: asInt(json, 'id'), + ); + + factory UserFollowerRequest.followers(String owner) => UserFollowerRequest( + jsonrpc: "2.0", + method: "condenser_api.get_followers", + params: [owner, null, "blog"], + id: 1); + + factory UserFollowerRequest.following(String owner) => UserFollowerRequest( + jsonrpc: "2.0", + method: "condenser_api.get_following", + params: [owner, null, "blog"], + id: 1); + + Map toJson() => { + 'jsonrpc': jsonrpc, + 'method': method, + 'params': params.map((e) => e).toList(), + 'id': id, + }; + + String toJsonString() => json.encode(toJson()); +} \ No newline at end of file diff --git a/lib/src/models/user_profile/response/followers_and_following.dart b/lib/src/models/user_profile/response/followers_and_following.dart new file mode 100644 index 00000000..59933fd8 --- /dev/null +++ b/lib/src/models/user_profile/response/followers_and_following.dart @@ -0,0 +1,55 @@ +import 'dart:convert'; +import 'package:acela/src/utils/safe_convert.dart'; + +class Followers { + // 2.0 + final String jsonrpc; + final List result; + // 1 + final int id; + + Followers({ + this.jsonrpc = "", + required this.result, + this.id = 0, + }); + + factory Followers.fromJson(Map? json) => Followers( + jsonrpc: asString(json, 'jsonrpc'), + result: asList(json, 'result').map((e) => FollowerItem.fromJson(e)).toList(), + id: asInt(json, 'id'), + ); + + Map toJson() => { + 'jsonrpc': jsonrpc, + 'result': result.map((e) => e.toJson()), + 'id': id, + }; +} + +class FollowerItem { + // lepe + final String follower; + // madefrance + final String following; + final List what; + + FollowerItem({ + this.follower = "", + this.following = "", + required this.what, + }); + + factory FollowerItem.fromJson(Map? json) => FollowerItem( + follower: asString(json, 'follower'), + following: asString(json, 'following'), + what: asList(json, 'what').map((e) => e.toString()).toList(), + ); + + Map toJson() => { + 'follower': follower, + 'following': following, + 'what': what.map((e) => e), + }; +} + diff --git a/lib/src/screens/user_channel_screen/user_channel_screen.dart b/lib/src/screens/user_channel_screen/user_channel_screen.dart index 2bb03521..ed559235 100644 --- a/lib/src/screens/user_channel_screen/user_channel_screen.dart +++ b/lib/src/screens/user_channel_screen/user_channel_screen.dart @@ -22,31 +22,48 @@ class UserChannelScreen extends StatefulWidget { _UserChannelScreenState createState() => _UserChannelScreenState(); } -class _UserChannelScreenState extends State { - List items = []; +class _UserChannelScreenState extends State with SingleTickerProviderStateMixin { + late TabController _tabController; + + static const List tabs = [ + Tab(text: 'About'), + Tab(text: 'Videos'), + Tab(text: 'Followers'), + Tab(text: 'Following'), + ]; + + + @override + void initState() { + super.initState(); + _tabController = TabController(length: tabs.length, vsync: this); + } + + @override + void dispose() { + super.dispose(); + _tabController.dispose(); + } Future loadUserProfile(String author) async { var client = http.Client(); var body = UserProfileRequest.forOwner(widget.owner).toJsonString(); var response = await client.post(Uri.parse(server.hiveDomain), body: body); if (response.statusCode == 200) { - _loadFeed(); return UserProfileResponse.fromString(response.body); } else { throw "Status code is ${response.statusCode}"; } } - - void _loadFeed() { - get(Uri.parse("${server.domain}/apiv2/feeds/@${widget.owner}")) - .then((value) { - if (value.statusCode == 200) { - List list = homeFeedItemFromString(value.body); - setState(() { - items = list; - }); - } - }); + + Future> loadFeed(String author) async { + var response = await get(Uri.parse("${server.domain}/apiv2/feeds/@${widget.owner}")); + if (response.statusCode == 200) { + List list = homeFeedItemFromString(response.body); + return list; + } else { + throw "Status code is ${response.statusCode}"; + } } Widget _tileTitle(HomeFeedItem item, BuildContext context, @@ -83,7 +100,6 @@ class _UserChannelScreenState extends State { height: 150, placeholder: 'assets/branding/three_speak_logo.png', image: url, - //data.result.metadata.profile.coverImage, fit: BoxFit.cover, imageErrorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { @@ -92,69 +108,65 @@ class _UserChannelScreenState extends State { ); } - Widget _thumbnail(String url, String name) { - return Container( - padding: const EdgeInsets.all(10), - child: Row( - children: [ - CustomCircleAvatar( - height: 100, - width: 100, - url: url), //data.result.metadata.profile.profileImage), - const SizedBox( - width: 10, - ), - Text( - name, - style: Theme.of(context).textTheme.displaySmall, - ), - ], - ), - ); - } - - Widget _bio(String bio) { - return Container( - padding: const EdgeInsets.all(10), - child: Expanded(child: Text(bio)), - ); - } - - Widget _userProfile(UserProfileResponse data) { - return ListView.separated( - itemBuilder: (context, index) { - if (index == 0) { - return _cover(data.result.metadata.profile.coverImage); - } else if (index == 1) { - return _thumbnail( - data.result.metadata.profile.profileImage, data.result.name); - } else if (index == 2) { - return _bio(data.result.metadata.profile.about); - } else { - return _listTile(items[index - 3], context, (item) { - log("tapped on item ${item.permlink}"); - Navigator.of(context).pushNamed( - VideoDetailsScreen.routeName(item.author, item.permlink)); - }, (owner) { - log("tapped on user ${owner.author}"); - }); - } - }, - separatorBuilder: (context, index) => - const Divider(thickness: 0, height: 1, color: Colors.transparent), - itemCount: items.length + 3, - ); + Widget _futureVideos() { + return FutureBuilder( + future: loadFeed(widget.owner), + builder: (context, snapshot) { + if (snapshot.hasError) { + return const Text('Error loading user profile'); + } else if (snapshot.hasData) { + var data = snapshot.data! as List; + return ListView.separated( + itemBuilder: (context, index) { + return _listTile(data[index], context, (item) { + log("tapped on item ${item.permlink}"); + Navigator.of(context).pushNamed( + VideoDetailsScreen.routeName(item.author, item.permlink)); + }, (owner) { + log("tapped on user ${owner.author}"); + }); + }, + separatorBuilder: (context, index) => + const Divider(thickness: 0, height: 1, color: Colors.transparent), + itemCount: data.length, + ); + } else { + return const LoadingScreen(); + } + }); } - Widget _futureBuilder() { + Widget _futureUserProfile() { return FutureBuilder( future: loadUserProfile(widget.owner), builder: (context, snapshot) { if (snapshot.hasError) { - return const Text('Firebase not initialized'); + return const Text('Error loading user profile'); } else if (snapshot.hasData) { var data = snapshot.data! as UserProfileResponse; - return _userProfile(data); + return Column( + children: [ + _cover(data.result.metadata.profile.coverImage), + const SizedBox(height: 10), + CustomCircleAvatar(height: 100, width: 100, url: data.result.metadata.profile.profileImage), + Text(widget.owner, style: Theme.of(context).textTheme.headline5), + const SizedBox(height: 10), + data.result.metadata.profile.about.isEmpty ? const Text('No Bio') : Text(data.result.metadata.profile.about), + const SizedBox(height: 10), + Text('Created at: ${Utilities.parseAndFormatDateTime(data.result.created)}'), + const SizedBox(height: 10), + Text('Last seen at: ${Utilities.parseAndFormatDateTime(data.result.active)}'), + const SizedBox(height: 10), + Text('Total Hive Posts: ${data.result.postCount}'), + const SizedBox(height: 10), + Text('Reputation: ${data.result.reputation}'), + const SizedBox(height: 10), + Text('Website: ${data.result.metadata.profile.website.isEmpty ? 'None' : data.result.metadata.profile.website}'), + const SizedBox(height: 10), + Text('Location: ${data.result.metadata.profile.location.isEmpty ? 'None' : data.result.metadata.profile.location}'), + const Spacer(), + ], + ); } else { return const LoadingScreen(); } @@ -162,13 +174,34 @@ class _UserChannelScreenState extends State { ); } + Widget _followers() { + + } + + Widget _following() { + + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.owner), + bottom: TabBar( + controller: _tabController, + tabs: tabs, + isScrollable: true, + ), + ), + body: TabBarView( + controller: _tabController, + children: [ + _futureUserProfile(), + _futureVideos(), + const Text('Followers'), + const Text('Following'), + ], ), - body: _futureBuilder(), ); } } diff --git a/lib/src/utils/seconds_to_duration.dart b/lib/src/utils/seconds_to_duration.dart index caeef4fb..767fb609 100644 --- a/lib/src/utils/seconds_to_duration.dart +++ b/lib/src/utils/seconds_to_duration.dart @@ -4,6 +4,11 @@ class Utilities { return '${(Duration(seconds: seconds))}'.split('.')[0].padLeft(8, '0'); } + static String parseAndFormatDateTime(String dateTime) { + var dt = DateTime.parse(dateTime); + return "${dt.year}-${dt.month}-${dt.year}"; + } + static String removeAllHtmlTags(String htmlText) { RegExp exp = RegExp( r"<[^>]*>", From cd46c2401706708e1c228d78cee02c38a1529006 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 4 Mar 2022 08:50:18 +0530 Subject: [PATCH 038/466] User channel page is complete. --- .flutter-plugins-dependencies | 2 +- .../response/followers_and_following.dart | 8 + .../follower_list_tile.dart | 86 +++++++++ .../user_channel_following.dart | 78 ++++++++ .../user_channel_profile.dart | 84 +++++++++ .../user_channel_screen.dart | 172 ++---------------- .../user_channel_videos.dart | 99 ++++++++++ .../video_details_tabbed_widget.dart | 10 +- lib/src/utils/seconds_to_duration.dart | 2 +- 9 files changed, 380 insertions(+), 161 deletions(-) create mode 100644 lib/src/screens/user_channel_screen/follower_list_tile.dart create mode 100644 lib/src/screens/user_channel_screen/user_channel_following.dart create mode 100644 lib/src/screens/user_channel_screen/user_channel_profile.dart create mode 100644 lib/src/screens/user_channel_screen/user_channel_videos.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 241fef56..655dc0b3 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-02 05:55:01.376560","version":"2.10.2"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-04 08:41:16.515793","version":"2.10.2"} \ No newline at end of file diff --git a/lib/src/models/user_profile/response/followers_and_following.dart b/lib/src/models/user_profile/response/followers_and_following.dart index 59933fd8..e40bf944 100644 --- a/lib/src/models/user_profile/response/followers_and_following.dart +++ b/lib/src/models/user_profile/response/followers_and_following.dart @@ -20,6 +20,10 @@ class Followers { id: asInt(json, 'id'), ); + factory Followers.fromJsonString(String jsonString) => Followers.fromJson( + json.decode(jsonString), + ); + Map toJson() => { 'jsonrpc': jsonrpc, 'result': result.map((e) => e.toJson()), @@ -46,6 +50,10 @@ class FollowerItem { what: asList(json, 'what').map((e) => e.toString()).toList(), ); + factory FollowerItem.fromJsonString(String jsonString) => FollowerItem.fromJson( + json.decode(jsonString), + ); + Map toJson() => { 'follower': follower, 'following': following, diff --git a/lib/src/screens/user_channel_screen/follower_list_tile.dart b/lib/src/screens/user_channel_screen/follower_list_tile.dart new file mode 100644 index 00000000..2c36e90e --- /dev/null +++ b/lib/src/screens/user_channel_screen/follower_list_tile.dart @@ -0,0 +1,86 @@ +import 'dart:developer'; + +import 'package:acela/src/bloc/server.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:acela/src/models/user_profile/request/user_profile_request.dart'; +import 'package:acela/src/models/user_profile/response/user_profile.dart'; +import 'package:acela/src/widgets/custom_circle_avatar.dart'; + +class FollowerListTile extends StatefulWidget { + const FollowerListTile({Key? key, required this.name}) : super(key: key); + final String name; + + @override + State createState() => _FollowerListTileState(); +} + +class _FollowerListTileState extends State + with AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + + Future _loadUserProfile() async { + var client = http.Client(); + var body = UserProfileRequest.forOwner(widget.name).toJsonString(); + var response = await client.post(Uri.parse(server.hiveDomain), body: body); + if (response.statusCode == 200) { + return UserProfileResponse.fromString(response.body); + } else { + throw "Status code is ${response.statusCode}"; + } + } + + Widget _futureUserProfile() { + return FutureBuilder( + future: _loadUserProfile(), + builder: (context, snapshot) { + if (snapshot.hasError) { + return ListTile(title: Text(widget.name)); + } else if (snapshot.hasData) { + var data = snapshot.data! as UserProfileResponse; + return ListTile( + leading: SizedBox( + height: 40, + width: 40, + child: FadeInImage.assetNetwork( + placeholder: 'assets/branding/three_speak_logo.png', + image: data.result.metadata.profile.profileImage, + fit: BoxFit.cover, + placeholderErrorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return Image.asset('assets/branding/three_speak_logo.png'); + }, + imageErrorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return Image.asset('assets/branding/three_speak_logo.png'); + }, + ), + ), + title: Text(widget.name), + subtitle: Text('Reputation: ${data.result.reputation}'), + ); + } else { + return ListTile(title: Text(widget.name)); + } + }, + ); + } + + @override + Widget build(BuildContext context) { + super.build(context); + // return _futureUserProfile(); + return ListTile( + leading: CustomCircleAvatar( + height: 40, + width: 40, + url: server.userOwnerThumb(widget.name), + ), + title: Text(widget.name), + onTap: () { + log('User tapped on hive user list item ${widget.name}'); + }, + ); + } +} diff --git a/lib/src/screens/user_channel_screen/user_channel_following.dart b/lib/src/screens/user_channel_screen/user_channel_following.dart new file mode 100644 index 00000000..ae602bd5 --- /dev/null +++ b/lib/src/screens/user_channel_screen/user_channel_following.dart @@ -0,0 +1,78 @@ +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/user_profile/request/user_followers_request.dart'; +import 'package:acela/src/models/user_profile/response/followers_and_following.dart'; +import 'package:acela/src/screens/user_channel_screen/follower_list_tile.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; + +class UserChannelFollowingWidget extends StatefulWidget { + const UserChannelFollowingWidget( + {Key? key, required this.owner, required this.isFollowers}) + : super(key: key); + final String owner; + final bool isFollowers; + + @override + State createState() => + _UserChannelFollowingWidgetState(); +} + +class _UserChannelFollowingWidgetState extends State + with AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + + Future _loadFollowers(String author) async { + var client = http.Client(); + var body = widget.isFollowers + ? UserFollowerRequest.followers(widget.owner).toJsonString() + : UserFollowerRequest.following(widget.owner).toJsonString(); + var response = await client.post(Uri.parse(server.hiveDomain), body: body); + if (response.statusCode == 200) { + return Followers.fromJsonString(response.body); + } else { + throw "Status code is ${response.statusCode}"; + } + } + + Widget _listTile(FollowerItem item) { + return FollowerListTile( + name: widget.isFollowers ? item.follower : item.following, + ); + } + + Widget _futureFollowers() { + return FutureBuilder( + future: _loadFollowers(widget.owner), + builder: (context, snapshot) { + if (snapshot.hasError) { + return const Text('Error loading user followers'); + } else if (snapshot.hasData) { + var data = snapshot.data! as Followers; + if (data.result.isEmpty) { + return Center( + child: Text('No ${widget.isFollowers ? 'Followers' : 'Followings'} found.'), + ); + } + return ListView.separated( + itemBuilder: (context, index) { + return _listTile(data.result[index]); + }, + separatorBuilder: (context, index) => const Divider( + thickness: 0, height: 1, color: Colors.transparent), + itemCount: data.result.length, + ); + } else { + return const LoadingScreen(); + } + }, + ); + } + + @override + Widget build(BuildContext context) { + super.build(context); + return _futureFollowers(); + } +} diff --git a/lib/src/screens/user_channel_screen/user_channel_profile.dart b/lib/src/screens/user_channel_screen/user_channel_profile.dart new file mode 100644 index 00000000..791f576b --- /dev/null +++ b/lib/src/screens/user_channel_screen/user_channel_profile.dart @@ -0,0 +1,84 @@ +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/utils/seconds_to_duration.dart'; +import 'package:acela/src/widgets/custom_circle_avatar.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:http/http.dart' as http; +import 'package:acela/src/models/user_profile/request/user_profile_request.dart'; +import 'package:acela/src/models/user_profile/response/user_profile.dart'; +import 'package:url_launcher/link.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class UserChannelProfileWidget extends StatefulWidget { + const UserChannelProfileWidget({Key? key, required this.owner}) : super(key: key); + final String owner; + + @override + State createState() => _UserChannelProfileWidgetState(); +} + +class _UserChannelProfileWidgetState extends State + with AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + + Future _loadUserProfile() async { + var client = http.Client(); + var body = UserProfileRequest.forOwner(widget.owner).toJsonString(); + var response = await client.post(Uri.parse(server.hiveDomain), body: body); + if (response.statusCode == 200) { + return UserProfileResponse.fromString(response.body); + } else { + throw "Status code is ${response.statusCode}"; + } + } + + Widget _cover(String url) { + return FadeInImage.assetNetwork( + height: 150, + placeholder: 'assets/branding/three_speak_logo.png', + image: url, + fit: BoxFit.cover, + imageErrorBuilder: + (BuildContext context, Object error, StackTrace? stackTrace) { + return Image.asset('assets/branding/three_speak_logo.png'); + }, + ); + } + + Widget _descriptionMarkDown(String markDown) { + return Markdown( + data: Utilities.removeAllHtmlTags(markDown), + onTapLink: (text, url, title) { + launch(url!); + }, + ); + } + + String _generateMarkDown(UserProfileResponse data) { + return "![cover image](${data.result.metadata.profile.coverImage})\n## Bio:\n${data.result.metadata.profile.about}\n\n\n## Created At:\n${Utilities.parseAndFormatDateTime(data.result.created)}\n\n## Last Seen At:\n${Utilities.parseAndFormatDateTime(data.result.active)}\n\n## Total Hive Posts:\n${data.result.postCount}\n\n## Hive Reputation:\n${data.result.reputation}\n\n## Location:\n${data.result.metadata.profile.location.isEmpty ? 'None' : data.result.metadata.profile.location}\n\n## Website:\n${data.result.metadata.profile.website.isEmpty ? 'None' : data.result.metadata.profile.website}"; + } + + Widget _futureUserProfile() { + return FutureBuilder( + future: _loadUserProfile(), + builder: (context, snapshot) { + if (snapshot.hasError) { + return const Text('Error loading user profile'); + } else if (snapshot.hasData) { + var data = snapshot.data! as UserProfileResponse; + return _descriptionMarkDown(_generateMarkDown(data)); + } else { + return const LoadingScreen(); + } + }, + ); + } + + @override + Widget build(BuildContext context) { + super.build(context); + return _futureUserProfile(); + } +} diff --git a/lib/src/screens/user_channel_screen/user_channel_screen.dart b/lib/src/screens/user_channel_screen/user_channel_screen.dart index ed559235..f038854e 100644 --- a/lib/src/screens/user_channel_screen/user_channel_screen.dart +++ b/lib/src/screens/user_channel_screen/user_channel_screen.dart @@ -1,18 +1,9 @@ -import 'dart:developer'; - import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; -import 'package:acela/src/models/user_profile/request/user_profile_request.dart'; -import 'package:acela/src/models/user_profile/response/user_profile.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; -import 'package:acela/src/utils/seconds_to_duration.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_following.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_profile.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_videos.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; -import 'package:acela/src/widgets/list_tile_video.dart'; -import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; -import 'package:http/http.dart' show get; -import 'package:timeago/timeago.dart' as timeago; class UserChannelScreen extends StatefulWidget { const UserChannelScreen({Key? key, required this.owner}) : super(key: key); @@ -45,148 +36,21 @@ class _UserChannelScreenState extends State with SingleTicker _tabController.dispose(); } - Future loadUserProfile(String author) async { - var client = http.Client(); - var body = UserProfileRequest.forOwner(widget.owner).toJsonString(); - var response = await client.post(Uri.parse(server.hiveDomain), body: body); - if (response.statusCode == 200) { - return UserProfileResponse.fromString(response.body); - } else { - throw "Status code is ${response.statusCode}"; - } - } - - Future> loadFeed(String author) async { - var response = await get(Uri.parse("${server.domain}/apiv2/feeds/@${widget.owner}")); - if (response.statusCode == 200) { - List list = homeFeedItemFromString(response.body); - return list; - } else { - throw "Status code is ${response.statusCode}"; - } - } - - Widget _tileTitle(HomeFeedItem item, BuildContext context, - Function(HomeFeedItem) onUserTap) { - String timeInString = - item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; - String owner = "👤 ${item.author}"; - String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; - String views = "▶ ${item.views}"; - return ListTileVideo( - placeholder: 'assets/branding/three_speak_logo.png', - url: item.images.thumbnail, - userThumbUrl: server.userOwnerThumb(item.author), - title: item.title, - subtitle: "$timeInString $owner $duration $views", - onUserTap: () { - onUserTap(item); - }, - ); - } - - Widget _listTile(HomeFeedItem item, BuildContext context, - Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { - return ListTile( - title: _tileTitle(item, context, onUserTap), - onTap: () { - onTap(item); - }, - ); - } - - Widget _cover(String url) { - return FadeInImage.assetNetwork( - height: 150, - placeholder: 'assets/branding/three_speak_logo.png', - image: url, - fit: BoxFit.cover, - imageErrorBuilder: - (BuildContext context, Object error, StackTrace? stackTrace) { - return Image.asset('assets/branding/three_speak_logo.png'); - }, - ); - } - - Widget _futureVideos() { - return FutureBuilder( - future: loadFeed(widget.owner), - builder: (context, snapshot) { - if (snapshot.hasError) { - return const Text('Error loading user profile'); - } else if (snapshot.hasData) { - var data = snapshot.data! as List; - return ListView.separated( - itemBuilder: (context, index) { - return _listTile(data[index], context, (item) { - log("tapped on item ${item.permlink}"); - Navigator.of(context).pushNamed( - VideoDetailsScreen.routeName(item.author, item.permlink)); - }, (owner) { - log("tapped on user ${owner.author}"); - }); - }, - separatorBuilder: (context, index) => - const Divider(thickness: 0, height: 1, color: Colors.transparent), - itemCount: data.length, - ); - } else { - return const LoadingScreen(); - } - }); - } - - Widget _futureUserProfile() { - return FutureBuilder( - future: loadUserProfile(widget.owner), - builder: (context, snapshot) { - if (snapshot.hasError) { - return const Text('Error loading user profile'); - } else if (snapshot.hasData) { - var data = snapshot.data! as UserProfileResponse; - return Column( - children: [ - _cover(data.result.metadata.profile.coverImage), - const SizedBox(height: 10), - CustomCircleAvatar(height: 100, width: 100, url: data.result.metadata.profile.profileImage), - Text(widget.owner, style: Theme.of(context).textTheme.headline5), - const SizedBox(height: 10), - data.result.metadata.profile.about.isEmpty ? const Text('No Bio') : Text(data.result.metadata.profile.about), - const SizedBox(height: 10), - Text('Created at: ${Utilities.parseAndFormatDateTime(data.result.created)}'), - const SizedBox(height: 10), - Text('Last seen at: ${Utilities.parseAndFormatDateTime(data.result.active)}'), - const SizedBox(height: 10), - Text('Total Hive Posts: ${data.result.postCount}'), - const SizedBox(height: 10), - Text('Reputation: ${data.result.reputation}'), - const SizedBox(height: 10), - Text('Website: ${data.result.metadata.profile.website.isEmpty ? 'None' : data.result.metadata.profile.website}'), - const SizedBox(height: 10), - Text('Location: ${data.result.metadata.profile.location.isEmpty ? 'None' : data.result.metadata.profile.location}'), - const Spacer(), - ], - ); - } else { - return const LoadingScreen(); - } - }, - ); - } - - Widget _followers() { - - } - - Widget _following() { - - } - @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(widget.owner), + title: Row( + children: [ + CustomCircleAvatar( + height: 40, + width: 40, + url: server.userOwnerThumb(widget.owner), + ), + const SizedBox(width: 10,), + Text(widget.owner) + ], + ), bottom: TabBar( controller: _tabController, tabs: tabs, @@ -196,10 +60,10 @@ class _UserChannelScreenState extends State with SingleTicker body: TabBarView( controller: _tabController, children: [ - _futureUserProfile(), - _futureVideos(), - const Text('Followers'), - const Text('Following'), + UserChannelProfileWidget(owner: widget.owner), + UserChannelVideos(owner: widget.owner), + UserChannelFollowingWidget(owner: widget.owner, isFollowers: true), + UserChannelFollowingWidget(owner: widget.owner, isFollowers: false), ], ), ); diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart new file mode 100644 index 00000000..55e75bb6 --- /dev/null +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -0,0 +1,99 @@ +import 'dart:developer'; + +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; +import 'package:acela/src/utils/seconds_to_duration.dart'; +import 'package:acela/src/widgets/list_tile_video.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' show get; +import 'package:timeago/timeago.dart' as timeago; + +class UserChannelVideos extends StatefulWidget { + const UserChannelVideos({Key? key, required this.owner}) : super(key: key); + final String owner; + + @override + State createState() => _UserChannelVideosState(); +} + +class _UserChannelVideosState extends State + with AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + + Future> loadFeed(String author) async { + var response = + await get(Uri.parse("${server.domain}/apiv2/feeds/@${widget.owner}")); + if (response.statusCode == 200) { + List list = homeFeedItemFromString(response.body); + return list; + } else { + throw "Status code is ${response.statusCode}"; + } + } + + Widget _tileTitle(HomeFeedItem item, BuildContext context, + Function(HomeFeedItem) onUserTap) { + String timeInString = + item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; + String owner = "👤 ${item.author}"; + String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; + String views = "▶ ${item.views}"; + return ListTileVideo( + placeholder: 'assets/branding/three_speak_logo.png', + url: item.images.thumbnail, + userThumbUrl: server.userOwnerThumb(item.author), + title: item.title, + subtitle: "$timeInString $owner $duration $views", + onUserTap: () { + onUserTap(item); + }, + ); + } + + Widget _listTile(HomeFeedItem item, BuildContext context, + Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { + return ListTile( + title: _tileTitle(item, context, onUserTap), + onTap: () { + onTap(item); + }, + ); + } + + Widget _futureVideos() { + return FutureBuilder( + future: loadFeed(widget.owner), + builder: (context, snapshot) { + if (snapshot.hasError) { + return const Text('Error loading user profile'); + } else if (snapshot.hasData) { + var data = snapshot.data! as List; + return ListView.separated( + itemBuilder: (context, index) { + return _listTile(data[index], context, (item) { + log("tapped on item ${item.permlink}"); + Navigator.of(context).pushNamed( + VideoDetailsScreen.routeName(item.author, item.permlink)); + }, (owner) { + log("tapped on user ${owner.author}"); + }); + }, + separatorBuilder: (context, index) => const Divider( + thickness: 0, height: 1, color: Colors.transparent), + itemCount: data.length, + ); + } else { + return const LoadingScreen(); + } + }, + ); + } + + @override + Widget build(BuildContext context) { + return _futureVideos(); + } +} diff --git a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart index 05331fd5..cea42692 100644 --- a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart +++ b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -// import 'dart:io' show Platform; +import 'dart:io' show Platform; import 'package:share_plus/share_plus.dart'; class VideoDetailsTabbedWidget extends StatefulWidget { @@ -61,11 +61,11 @@ class _VideoDetailsTabbedWidgetState extends State }, icon: const Icon(Icons.share), ); - // if (Platform.isAndroid || Platform.isIOS) { - // return [channelButton, shareButton]; - // } else { + if (Platform.isAndroid || Platform.isIOS) { + return [channelButton, shareButton]; + } else { return [channelButton]; - // } + } } @override diff --git a/lib/src/utils/seconds_to_duration.dart b/lib/src/utils/seconds_to_duration.dart index 767fb609..66b08bb4 100644 --- a/lib/src/utils/seconds_to_duration.dart +++ b/lib/src/utils/seconds_to_duration.dart @@ -6,7 +6,7 @@ class Utilities { static String parseAndFormatDateTime(String dateTime) { var dt = DateTime.parse(dateTime); - return "${dt.year}-${dt.month}-${dt.year}"; + return "${dt.year}-${dt.month}-${dt.day}"; } static String removeAllHtmlTags(String htmlText) { From d3a655b2f901e0b4020c44b806621b2d1f63aebe Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 4 Mar 2022 16:38:13 +0530 Subject: [PATCH 039/466] community details work in progress. --- .flutter-plugins-dependencies | 2 +- .../request/communities_request_model.dart | 5 +- .../request/community_details_request.dart | 75 +++++++++ .../community_details_response_models.dart | 142 ++++++++++++++++ .../communities_screen.dart | 3 +- .../community_details_screen.dart | 155 ++++++++++++++++-- lib/src/screens/home_screen/home_screen.dart | 45 +++-- lib/src/utils/safe_convert.dart | 6 + 8 files changed, 400 insertions(+), 33 deletions(-) create mode 100644 lib/src/models/communities_models/request/community_details_request.dart create mode 100644 lib/src/models/communities_models/response/community_details_response_models.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 655dc0b3..33132757 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-04 08:41:16.515793","version":"2.10.2"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-04 16:25:13.145146","version":"2.10.2"} \ No newline at end of file diff --git a/lib/src/models/communities_models/request/communities_request_model.dart b/lib/src/models/communities_models/request/communities_request_model.dart index c3252c98..85e84f25 100644 --- a/lib/src/models/communities_models/request/communities_request_model.dart +++ b/lib/src/models/communities_models/request/communities_request_model.dart @@ -1,9 +1,6 @@ import 'package:acela/src/utils/safe_convert.dart'; import 'dart:convert'; -String communitiesRequestModelToJson(CommunitiesRequestModel data) => - json.encode(data.toJson()); - class CommunitiesRequestModel { final CommunitiesRequestParams params; @@ -37,6 +34,8 @@ class CommunitiesRequestModel { 'method': method, 'id': id, }; + + String toJsonString() => json.encode(toJson()); } class CommunitiesRequestParams { diff --git a/lib/src/models/communities_models/request/community_details_request.dart b/lib/src/models/communities_models/request/community_details_request.dart new file mode 100644 index 00000000..6a04b784 --- /dev/null +++ b/lib/src/models/communities_models/request/community_details_request.dart @@ -0,0 +1,75 @@ +import 'package:acela/src/utils/safe_convert.dart'; +import 'dart:convert'; + +class CommunityDetailsRequest { + final CommunityDetailsRequestParams params; + + // 2.0 + final String jsonrpc; + + // bridge.get_community + final String method; + + // 1 + final int id; + + CommunityDetailsRequest({ + required this.params, + this.jsonrpc = "", + this.method = "", + this.id = 0, + }); + + factory CommunityDetailsRequest.fromJson(Map? json) => + CommunityDetailsRequest( + params: CommunityDetailsRequestParams.fromJson(asMap(json, 'params')), + jsonrpc: asString(json, 'jsonrpc'), + method: asString(json, 'method'), + id: asInt(json, 'id'), + ); + + factory CommunityDetailsRequest.forName(String name) { + return CommunityDetailsRequest( + params: CommunityDetailsRequestParams.forName(name), + jsonrpc: "2.0", + method: "bridge.get_community", + id: 1, + ); + } + + Map toJson() => { + 'params': params.toJson(), + 'jsonrpc': jsonrpc, + 'method': method, + 'id': id, + }; + + String toJsonString() => json.encode(toJson()); +} + +class CommunityDetailsRequestParams { + // hive-167922 + final String name; + + // sagarkothari88 + final String observer; + + CommunityDetailsRequestParams({ + this.name = "", + this.observer = "", + }); + + factory CommunityDetailsRequestParams.fromJson(Map? json) => + CommunityDetailsRequestParams( + name: asString(json, 'name'), + observer: asString(json, 'observer'), + ); + + factory CommunityDetailsRequestParams.forName(String name) => + CommunityDetailsRequestParams(name: name, observer: 'sagarkothari88'); + + Map toJson() => { + 'name': name, + 'observer': observer, + }; +} diff --git a/lib/src/models/communities_models/response/community_details_response_models.dart b/lib/src/models/communities_models/response/community_details_response_models.dart new file mode 100644 index 00000000..1fcddcdd --- /dev/null +++ b/lib/src/models/communities_models/response/community_details_response_models.dart @@ -0,0 +1,142 @@ +import 'dart:developer'; + +import 'package:acela/src/utils/safe_convert.dart'; +import 'dart:convert'; + +class CommunityDetailsResponse { + // 2.0 + final String jsonrpc; + final CommunityDetailsResponseResult result; + + // 1 + final int id; + + CommunityDetailsResponse({ + this.jsonrpc = "", + required this.result, + this.id = 0, + }); + + factory CommunityDetailsResponse.fromJson(Map? json) => + CommunityDetailsResponse( + jsonrpc: asString(json, 'jsonrpc'), + result: CommunityDetailsResponseResult.fromJson(asMap(json, 'result')), + id: asInt(json, 'id'), + ); + + factory CommunityDetailsResponse.fromString(String string) => + CommunityDetailsResponse.fromJson(json.decode(string)); + + Map toJson() => { + 'jsonrpc': jsonrpc, + 'result': result.toJson(), + 'id': id, + }; +} + +class CommunityDetailsResponseResult { + // 1341662 + final int id; + + // hive-167922 + final String name; + + // LeoFinance + final String title; + + // LeoFinance is a community for crypto & finance. Powered by Hive and the LEO token economy. + final String about; + + // en + final String lang; + + // 1 + final int typeId; + + // false + final bool isNsfw; + + // 12009 + final int subscribers; + + // 2019-11-26 17:25:27 + final String createdAt; + + // 22177 + final int sumPending; + + // 12112 + final int numPending; + + // 1435 + final int numAuthors; + final String avatarUrl; + + // Using our Hive-based token (LEO) we reward content creators and users for engaging on our platform at https://leofinance.io and within our community on the Hive blockchain. Blogging is just the beginning of what's possible in the LeoFinance community and with the LEO token:1). Trade LEO and other Hive-based tokens on our exchange: https://leodex.io2). Track your Hive account statistics at https://hivestats.io3). Opt-in to ads on LEO Apps which drives value back into the LEO token economy from ad buybacks.4). Learn & contribute to our crypto-educational resource at https://leopedia.io5). Wrap LEO onto the Ethereum blockchain with our cross-chain token bridge: https://wleo.io (coming soon)Learn more about us at https://leopedia.io/faq + final String description; + + // Content should be related to the financial space (i.e. crypto, equities, etc. etc.)Posts created from our interface (https://leofinance.io) are eligible for upvotes from @leo.voter and will automatically be posted to our Hive community, our front end and other Hive front ends as wellPosts in our community are also eligible to earn our native token (LEO) in conjunction with HIVE post rewardsIf you have any questions or need help with anything, feel free to reach out to us on twitter (@financeleo) or head over to our discord server (https://discord.gg/KgcVDKQ) + final String flagText; + final List> team; + + CommunityDetailsResponseResult({ + this.id = 0, + this.name = "", + this.title = "", + this.about = "", + this.lang = "", + this.typeId = 0, + this.isNsfw = false, + this.subscribers = 0, + this.createdAt = "", + this.sumPending = 0, + this.numPending = 0, + this.numAuthors = 0, + this.avatarUrl = "", + this.description = "", + this.flagText = "", + required this.team, + }); + + factory CommunityDetailsResponseResult.fromJson(Map? json) => + CommunityDetailsResponseResult( + id: asInt(json, 'id'), + name: asString(json, 'name'), + title: asString(json, 'title'), + about: asString(json, 'about'), + lang: asString(json, 'lang'), + typeId: asInt(json, 'type_id'), + isNsfw: asBool(json, 'is_nsfw'), + subscribers: asInt(json, 'subscribers'), + createdAt: asString(json, 'created_at'), + sumPending: asInt(json, 'sum_pending'), + numPending: asInt(json, 'num_pending'), + numAuthors: asInt(json, 'num_authors'), + avatarUrl: asString(json, 'avatar_url'), + description: asString(json, 'description'), + flagText: asString(json, 'flag_text'), + team: asList(json, 'team').map((e) { + log("Console message goes here"); + return (e as List).map((s) => asDynamicString(s)).toList(); + }).toList(), + ); + + Map toJson() => { + 'id': id, + 'name': name, + 'title': title, + 'about': about, + 'lang': lang, + 'type_id': typeId, + 'is_nsfw': isNsfw, + 'subscribers': subscribers, + 'created_at': createdAt, + 'sum_pending': sumPending, + 'num_pending': numPending, + 'num_authors': numAuthors, + 'avatar_url': avatarUrl, + 'description': description, + 'flag_text': flagText, + 'team': team.map((e) => e), + }; +} diff --git a/lib/src/screens/communities_screen/communities_screen.dart b/lib/src/screens/communities_screen/communities_screen.dart index 780ff401..b41db8b4 100644 --- a/lib/src/screens/communities_screen/communities_screen.dart +++ b/lib/src/screens/communities_screen/communities_screen.dart @@ -19,8 +19,7 @@ class CommunitiesScreen extends StatefulWidget { class _CommunitiesScreenState extends State { Future> getData() async { var client = http.Client(); - var body = communitiesRequestModelToJson( - CommunitiesRequestModel(params: CommunitiesRequestParams())); + var body = CommunitiesRequestModel(params: CommunitiesRequestParams()).toJsonString(); var response = await client.post(Uri.parse(server.hiveDomain), body: body); if (response.statusCode == 200) { var communitiesResponse = diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index c12f8919..14a6e0e8 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -1,16 +1,24 @@ import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/communities_models/request/community_details_request.dart'; +import 'package:acela/src/models/communities_models/response/community_details_response_models.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; +import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/retry.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:http/http.dart'; import 'package:timeago/timeago.dart' as timeago; +import 'package:http/http.dart' as http; +import 'package:url_launcher/url_launcher.dart'; class CommunityDetailScreen extends StatefulWidget { - const CommunityDetailScreen({Key? key, required this.name, required this.title}) : super(key: key); + const CommunityDetailScreen( + {Key? key, required this.name, required this.title}) + : super(key: key); final String name; final String title; @@ -18,12 +26,22 @@ class CommunityDetailScreen extends StatefulWidget { _CommunityDetailScreenState createState() => _CommunityDetailScreenState(); } -class _CommunityDetailScreenState extends State { +class _CommunityDetailScreenState extends State + with SingleTickerProviderStateMixin { + late TabController _tabController; + + static const List tabs = [ + Tab(text: 'About'), + Tab(text: 'Videos'), + Tab(text: 'Team') + ]; + late Future> _loadingFeed; + late Future _details; - Future> loadHomeFeed() async { - var uri = Uri.parse( - 'https://3speak.tv/apiv2/feeds/community/${widget.name}/new'); + Future> _loadHomeFeed() async { + var uri = + Uri.parse('https://3speak.tv/apiv2/feeds/community/${widget.name}/new'); var response = await get(uri); if (response.statusCode == 200) { List list = homeFeedItemFromString(response.body); @@ -33,10 +51,29 @@ class _CommunityDetailScreenState extends State { } } + Future _loadDetails() async { + var client = http.Client(); + var body = CommunityDetailsRequest.forName(widget.name).toJsonString(); + var response = await client.post(Uri.parse(server.hiveDomain), body: body); + if (response.statusCode == 200) { + return CommunityDetailsResponse.fromString(response.body); + } else { + throw "Status code is ${response.statusCode}"; + } + } + @override void initState() { super.initState(); - _loadingFeed = loadHomeFeed(); + _loadingFeed = _loadHomeFeed(); + _details = _loadDetails(); + _tabController = TabController(length: tabs.length, vsync: this); + } + + @override + void dispose() { + super.dispose(); + _tabController.dispose(); } void onTap(HomeFeedItem item) { @@ -51,7 +88,7 @@ class _CommunityDetailScreenState extends State { Widget _tileTitle(HomeFeedItem item, BuildContext context, Function(HomeFeedItem) onUserTap) { String timeInString = - item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; + item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; String owner = "👤 ${item.author}"; String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; String views = "▶ ${item.views}"; @@ -81,16 +118,15 @@ class _CommunityDetailScreenState extends State { Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { return RefreshIndicator( onRefresh: onRefresh, - child:ListView.separated( + child: ListView.separated( physics: const AlwaysScrollableScrollPhysics(), itemBuilder: (context, index) { return _listTile(list[index], context, onTap, onUserTap); }, - separatorBuilder: (context, index) => const Divider( - thickness: 0, height: 1, color: Colors.transparent), + separatorBuilder: (context, index) => + const Divider(thickness: 0, height: 1, color: Colors.transparent), itemCount: list.length, - ) - ); + )); } Widget _screen() { @@ -100,10 +136,75 @@ class _CommunityDetailScreenState extends State { if (snapshot.hasError) { return RetryScreen( error: snapshot.error?.toString() ?? 'Something went wrong', - onRetry: loadHomeFeed); + onRetry: _loadHomeFeed); } else if (snapshot.hasData) { List items = snapshot.data! as List; - return list(items, loadHomeFeed, onTap, onUserTap); + return list(items, _loadHomeFeed, onTap, onUserTap); + } else { + return const LoadingScreen(); + } + }, + ); + } + + String _generateMarkDown(CommunityDetailsResponse data) { + return "## About:\n${data.result.about}\n\n## Information:\n${data.result.description}\n\n## Flags:\n${data.result.flagText}\n\n## Total Authors:\n${data.result.numAuthors}\n\n## Subscribers:\n${data.result.subscribers}\n\n## Pending Rewards:\n\$${data.result.sumPending}\n\n## Created At:\n${Utilities.parseAndFormatDateTime(data.result.createdAt)}"; + } + + Widget _descriptionMarkDown(String markDown) { + return Markdown( + data: Utilities.removeAllHtmlTags(markDown), + onTapLink: (text, url, title) { + launch(url!); + }, + ); + } + + Widget _about() { + return FutureBuilder( + future: _details, + builder: (builder, snapshot) { + if (snapshot.hasError) { + return RetryScreen( + error: snapshot.error?.toString() ?? 'Something went wrong', + onRetry: _loadDetails); + } else if (snapshot.hasData) { + CommunityDetailsResponse data = + snapshot.data! as CommunityDetailsResponse; + return _descriptionMarkDown(_generateMarkDown(data)); + } else { + return const LoadingScreen(); + } + }, + ); + } + + Widget _team() { + return FutureBuilder( + future: _details, + builder: (builder, snapshot) { + if (snapshot.hasError) { + return RetryScreen( + error: snapshot.error?.toString() ?? 'Something went wrong', + onRetry: _loadDetails); + } else if (snapshot.hasData) { + CommunityDetailsResponse data = + snapshot.data! as CommunityDetailsResponse; + return ListView.separated( + itemBuilder: (context, index) { + return ListTile( + leading: CustomCircleAvatar( + height: 40, + width: 40, + url: server.userOwnerThumb(data.result.team[index][0]), + ), + title: Text(data.result.team[index][0]), + subtitle: Text(data.result.team[index][1]), + ); + }, + separatorBuilder: (context, index) => const Divider(), + itemCount: data.result.team.length, + ); } else { return const LoadingScreen(); } @@ -115,9 +216,31 @@ class _CommunityDetailScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(widget.title), + title: Row( + children: [ + CustomCircleAvatar( + height: 40, + width: 40, + url: server.communityIcon(widget.name), + ), + const SizedBox(width: 10), + Text(widget.title) + ], + ), + bottom: TabBar( + controller: _tabController, + tabs: tabs, + isScrollable: true, + ), + ), + body: TabBarView( + controller: _tabController, + children: [ + _about(), + _screen(), + _team(), + ], ), - body: _screen(), ); } } diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index e3ee976e..9776147f 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -7,13 +7,12 @@ import 'package:flutter/material.dart'; import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; class HomeScreen extends StatefulWidget { - const HomeScreen( - {Key? key, - required this.path, - required this.showDrawer, - required this.title, - required this.isDarkMode, - required this.switchDarkMode}) + const HomeScreen({Key? key, + required this.path, + required this.showDrawer, + required this.title, + required this.isDarkMode, + required this.switchDarkMode}) : super(key: key); final String path; final bool showDrawer; @@ -66,18 +65,42 @@ class _HomeScreenState extends State { ); } + Widget _threeSpeakIcon() { + return SizedBox( + height: 40, + width: 40, + child: CircleAvatar( + backgroundImage: Image + .asset("assets/branding/three_speak_icon.png") + .image, + backgroundColor: Colors.transparent, + radius: 100, + ), + ); + } + + Widget _header() { + return Row( + children: [ + _threeSpeakIcon(), + const SizedBox(width: 10), + Text(widget.title), + ] + ); + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(widget.title), + title: Text(widget.title), //_header(), ), body: _screen(), drawer: widget.showDrawer ? DrawerScreen( - isDarkMode: widget.isDarkMode, - switchDarkMode: widget.switchDarkMode, - ) + isDarkMode: widget.isDarkMode, + switchDarkMode: widget.switchDarkMode, + ) : null, ); } diff --git a/lib/src/utils/safe_convert.dart b/lib/src/utils/safe_convert.dart index c2fc21f2..9775a25d 100644 --- a/lib/src/utils/safe_convert.dart +++ b/lib/src/utils/safe_convert.dart @@ -46,6 +46,12 @@ String asString(Map? json, String key, {String defaultValue = " return defaultValue; } +String asDynamicString(dynamic value) { + if (value == null) return ""; + if (value is String) return value; + return ""; +} + Map asMap(Map? json, String key, {Map? defaultValue}) { if (json == null || !json.containsKey(key)) return defaultValue ?? {}; var value = json[key]; From f04176454b3669c8e12338c979a84cb2e954991e Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 8 Mar 2022 08:39:00 +0530 Subject: [PATCH 040/466] new video details in progress. --- .flutter-plugins-dependencies | 2 +- ios/Runner.xcodeproj/project.pbxproj | 15 +- ios/Runner/Info.plist | 2 +- .../video_details_screen.dart | 175 +++++++++++++----- .../video_details_tabbed_widget.dart | 29 ++- lib/src/widgets/video_player.dart | 3 +- 6 files changed, 159 insertions(+), 67 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 33132757..6b3236bb 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-04 16:25:13.145146","version":"2.10.2"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-08 08:32:44.728136","version":"2.10.2"} \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 2b8415a7..d5d51a33 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -332,6 +332,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 4; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -344,6 +345,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MARKETING_VERSION = 1.0.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -358,7 +360,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -366,6 +368,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.3speak.Acela; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -404,6 +407,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 4; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -422,6 +426,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MARKETING_VERSION = 1.0.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -459,6 +464,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 4; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -471,6 +477,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MARKETING_VERSION = 1.0.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -487,7 +494,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -495,6 +502,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.3speak.Acela; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -510,7 +518,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -518,6 +526,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.3speak.Acela; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 74963471..1ca996e7 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) + $(MARKETING_VERSION) CFBundleSignature ???? CFBundleVersion diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index b36992bd..d338c115 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -1,15 +1,16 @@ +import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_recommendation.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_tabbed_widget.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; +import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/video_player.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:timeago/timeago.dart' as timeago; class VideoDetailsScreen extends StatefulWidget { const VideoDetailsScreen({Key? key, required this.vm}) : super(key: key); @@ -24,56 +25,147 @@ class VideoDetailsScreen extends StatefulWidget { } class _VideoDetailsScreenState extends State { - var fullscreen = false; - void onUserTap() { Navigator.of(context).pushNamed("/userChannel/${widget.vm.author}"); } Widget container(String title, Widget body) { return Scaffold( - appBar: fullscreen - ? null - : AppBar( - title: Text(title), - actions: [ - IconButton( - onPressed: onUserTap, - icon: const Icon(Icons.person), - ), - ], - ), body: body, ); } Widget descriptionMarkDown(String markDown) { + return Markdown( + data: Utilities.removeAllHtmlTags(markDown), + onTapLink: (text, url, title) { + launch(url!); + }, + ); + } + + Widget titleAndSubtitle(VideoDetails details) { + String string = + "📆 ${timeago.format(DateTime.parse(details.created))} · ▶ ${details.views} views · 👥 ${details.community}"; + return InkWell( + child: Container( + margin: const EdgeInsets.all(10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(details.title, + style: Theme.of(context).textTheme.bodyLarge), + const SizedBox(height: 3), + Text(string, style: Theme.of(context).textTheme.bodySmall), + ], + ), + ), + const Icon(Icons.keyboard_arrow_down_outlined), + ], + ), + ), + onTap: () { + log('Hello'); + }, + ); + } + + Widget listTile(HiveComment comment) { + var item = comment; + var userThumb = server.userOwnerThumb(item.author); + var author = item.author; + var body = item.body; + var upVotes = item.activeVotes.where((e) => e.percent > 0).length; + var downVotes = item.activeVotes.where((e) => e.percent < 0).length; + var payout = item.pendingPayoutValue.replaceAll(" HBD", ""); + var timeInString = + item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; + var text = + "👤 $author 👍 $upVotes 👎 $downVotes 💰 $payout $timeInString"; + // var depth = (item.depth * 25.0) - 25; + double width = MediaQuery.of(context).size.width - 90; return Container( margin: const EdgeInsets.all(10), - child: Markdown( - data: Utilities.removeAllHtmlTags(markDown), - onTapLink: (text, url, title) { - launch(url!); - }, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CustomCircleAvatar(height: 25, width: 25, url: userThumb), + Container(margin: const EdgeInsets.only(right: 10)), + SizedBox( + width: width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MarkdownBody( + data: Utilities.removeAllHtmlTags(body), + shrinkWrap: true, + onTapLink: (text, url, title) { + launch(url!); + }, + ), + Container(margin: const EdgeInsets.only(bottom: 10)), + Text( + text, + style: Theme.of(context).textTheme.bodyText1, + ), + ], + ), + ), + const Icon(Icons.expand) + ], ), - // Html(data: markdownToHtml(markDown)), ); } - List tabBarChildren(VideoDetails details) { - return [ - SPKVideoPlayer( - playUrl: details.playUrl, - handleFullScreen: (value) { - setState(() { - fullscreen = value; - }); - }, - ), - descriptionMarkDown(details.description), - VideoDetailsCommentsWidget(vm: widget.vm), - VideoDetailsRecommendationWidget(vm: widget.vm), - ]; + Widget commentsSection(List comments) { + if (comments.isEmpty) { + return Container( + margin: const EdgeInsets.all(10), + child: const Text('No comments added'), + ); + } + return InkWell( + child: listTile(comments.last), + onTap: () { + + }, + ); + } + + Widget videoWithDetails(VideoDetails details) { + return ListView( + children: [ + SizedBox( + height: 230, + child: SPKVideoPlayer( + playUrl: details.playUrl, + ), + ), + titleAndSubtitle(details), + videoComments(), + ], + ); + } + + Widget videoComments() { + return FutureBuilder( + future: widget.vm.loadComments(widget.vm.author, widget.vm.permlink), + builder: (builder, snapshot) { + if (snapshot.hasError) { + String text = + 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; + return Container(margin: const EdgeInsets.all(10), child: Text(text)); + } else if (snapshot.hasData) { + var data = snapshot.data! as List; + return commentsSection(data); + } else { + return Container(margin: const EdgeInsets.all(10), child: const Text('Loading comments')); + } + }); } @override @@ -88,13 +180,10 @@ class _VideoDetailsScreenState extends State { } else if (snapshot.hasData) { var data = snapshot.data as VideoDetails?; if (data != null) { - return VideoDetailsTabbedWidget( - children: tabBarChildren(data), - title: data.title, - onUserTap: onUserTap, - fullscreen: fullscreen, - routeName: - "${server.domain}${VideoDetailsScreen.routeName(data.owner, data.permlink)}", + return Scaffold( + body: SafeArea( + child: videoWithDetails(data), + ), ); } else { return container( diff --git a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart index cea42692..ac20548d 100644 --- a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart +++ b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart @@ -25,7 +25,6 @@ class VideoDetailsTabbedWidget extends StatefulWidget { class _VideoDetailsTabbedWidgetState extends State with SingleTickerProviderStateMixin { static const List tabs = [ - Tab(text: 'Video'), Tab(text: 'Description'), Tab(text: 'Comments'), Tab(text: 'Recommendation'), @@ -70,22 +69,18 @@ class _VideoDetailsTabbedWidgetState extends State @override Widget build(BuildContext context) { - return Scaffold( - appBar: widget.fullscreen - ? null - : AppBar( - title: Text(widget.title), - actions: _buttons(), - bottom: TabBar( - controller: _tabController, - isScrollable: true, - tabs: tabs, - ), - ), - body: TabBarView( - controller: _tabController, - children: widget.children, - ), + return Column( + children: [ + TabBar( + controller: _tabController, + isScrollable: true, + tabs: tabs, + ), + TabBarView( + controller: _tabController, + children: widget.children, + ), + ], ); } } diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index bb25e037..7673bd24 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -5,10 +5,9 @@ import 'package:chewie/chewie.dart'; class SPKVideoPlayer extends StatefulWidget { const SPKVideoPlayer( - {Key? key, required this.playUrl, required this.handleFullScreen}) + {Key? key, required this.playUrl}) : super(key: key); final String playUrl; - final Function(bool) handleFullScreen; @override _SPKVideoPlayerState createState() => _SPKVideoPlayerState(); From d32474534e2a5e9c8f4c8d06a109eea0ee82b944 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 9 Mar 2022 12:06:22 +0530 Subject: [PATCH 041/466] video details work in progress. --- .env | 1 + .flutter-plugins | 10 +- .flutter-plugins-dependencies | 2 +- .gitignore | 4 +- .idea/libraries/Dart_Packages.xml | 60 ++--- .idea/libraries/Flutter_Plugins.xml | 10 +- .packages | 26 +- lib/main.dart | 39 +-- .../video_details_screen.dart | 223 ++++++++++++------ lib/src/widgets/video_player.dart | 4 + pubspec.lock | 38 +-- pubspec.yaml | 2 + 12 files changed, 258 insertions(+), 161 deletions(-) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 00000000..8a267824 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +HIVE_SEARCHER_AUTH_KEY=QFS2JICIIZJLHEYGA4XOLRTAQQP0XLVC6B9GU0NQCLWAFNGL6JGZKPUECPL6 \ No newline at end of file diff --git a/.flutter-plugins b/.flutter-plugins index 612fe620..9d6ba3ff 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,6 +1,6 @@ # This is a generated file; do not edit or check into version control. -firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/ -firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/ +firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/ +firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/ share_plus=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/ share_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/ share_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/ @@ -9,13 +9,13 @@ url_launcher_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlan url_launcher_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/ url_launcher_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/ url_launcher_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/ -url_launcher_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/ +url_launcher_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/ url_launcher_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/ -video_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.18/ +video_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.3.0/ video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/ video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/ video_player_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/ video_player_web_hls=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/ -wakelock=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/ +wakelock=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/ wakelock_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/ wakelock_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 6b3236bb..e6423ab2 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-08 08:32:44.728136","version":"2.10.2"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-09 09:34:14.536418","version":"2.10.3"} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 54f88372..48dec40f 100644 --- a/.gitignore +++ b/.gitignore @@ -89,4 +89,6 @@ fastlane/test_output iOSInjectionProject/ -.dart_tool \ No newline at end of file +.dart_tool +.env +*.env \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index ee9d094b..1990b2ed 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -5,14 +5,14 @@ - - @@ -121,13 +121,6 @@ - - - - - - @@ -180,7 +173,7 @@ - @@ -208,21 +201,21 @@ - - - @@ -240,6 +233,13 @@ + + + + + + @@ -341,7 +341,7 @@ - @@ -439,7 +439,7 @@ - @@ -642,7 +642,7 @@ - @@ -670,7 +670,7 @@ - @@ -712,7 +712,7 @@ - @@ -775,8 +775,8 @@ - - + + @@ -792,7 +792,6 @@ - @@ -800,14 +799,15 @@ - + - - - + + + + @@ -820,7 +820,7 @@ - + @@ -834,7 +834,7 @@ - + @@ -862,17 +862,17 @@ - + - + - + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index e41217bd..8f24dea2 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,26 +1,26 @@ - - - - - + + + + + diff --git a/.packages b/.packages index 14f9a630..5697edb3 100644 --- a/.packages +++ b/.packages @@ -3,9 +3,9 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-02-23 08:13:21.030953. -_fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-34.0.0/lib/ -analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.2.0/lib/ +# Generated by pub on 2022-03-09 07:00:46.405558. +_fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ +analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ boolean_selector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/ @@ -21,7 +21,6 @@ characters:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.o charcode:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib/ checked_yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/checked_yaml-2.0.1/lib/ chewie:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/chewie-1.3.0/lib/ -cli_util:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cli_util-0.3.5/lib/ clock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib/ code_builder:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/code_builder-4.1.0/lib/ collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0/lib/ @@ -29,15 +28,16 @@ convert:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ crypto:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.1/lib/ csslib:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.17.1/lib/ cupertino_icons:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.4/lib/ -dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.1/lib/ +dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.2/lib/ fake_async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0/lib/ ffi:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.1.2/lib/ file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib/ -firebase_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.12.0/lib/ -firebase_core_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_platform_interface-4.2.4/lib/ -firebase_core_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.5.4/lib/ +firebase_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/lib/ +firebase_core_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_platform_interface-4.2.5/lib/ +firebase_core_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/lib/ fixnum:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fixnum-1.0.0/lib/ flutter:file:///Applications/flutter/flutter/packages/flutter/lib/ +flutter_dotenv:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_dotenv-5.0.2/lib/ flutter_lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib/ flutter_markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_markdown-0.6.9/lib/ flutter_test:file:///Applications/flutter/flutter/packages/flutter_test/lib/ @@ -52,7 +52,7 @@ http_parser:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang. io:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/io-1.0.3/lib/ js:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3/lib/ json_annotation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_annotation-4.4.0/lib/ -json_serializable:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_serializable-6.1.4/lib/ +json_serializable:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_serializable-6.1.5/lib/ lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib/ logging:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/logging-1.0.2/lib/ markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/markdown-4.0.1/lib/ @@ -66,7 +66,7 @@ path:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pat plugin_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2/lib/ pool:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pool-1.5.0/lib/ provider:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/provider-6.0.2/lib/ -pub_semver:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pub_semver-2.1.0/lib/ +pub_semver:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pub_semver-2.1.1/lib/ pubspec_parse:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pubspec_parse-1.2.0/lib/ share_plus:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/lib/ share_plus_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-2.0.4/lib/ @@ -95,17 +95,17 @@ url_launcher_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dart url_launcher_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/lib/ url_launcher_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/lib/ url_launcher_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_platform_interface-2.0.5/lib/ -url_launcher_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.8/lib/ +url_launcher_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/lib/ url_launcher_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/lib/ vector_math:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.1/lib/ very_good_analysis:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/very_good_analysis-2.4.0/lib/ -video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.2.18/lib/ +video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.3.0/lib/ video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/lib/ video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/lib/ video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.0/lib/ video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/lib/ video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/lib/ -wakelock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+1/lib/ +wakelock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/lib/ wakelock_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/lib/ wakelock_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_platform_interface-0.3.0/lib/ wakelock_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/lib/ diff --git a/lib/main.dart b/lib/main.dart index ca931211..506d445f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,10 +8,12 @@ import 'package:acela/src/screens/video_details_screen/video_details_view_model. import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'firebase_options.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'src/bloc/server.dart'; Future main() async { + await dotenv.load(fileName: ".env"); WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); } @@ -30,22 +32,24 @@ class _MyAppState extends State { Widget futureBuilder(Widget withWidget) { return FutureBuilder( - future: _fbApp, - builder: (context, snapshot) { - if (snapshot.hasError) { - return const Text('Firebase not initialized'); - } else if (snapshot.hasData) { - return withWidget; - } else { - return const CircularProgressIndicator(); - } - }); + future: _fbApp, + builder: (context, snapshot) { + if (snapshot.hasError) { + return const Text('Firebase not initialized'); + } else if (snapshot.hasData) { + return withWidget; + } else { + return const CircularProgressIndicator(); + } + }, + ); } - MaterialPageRoute configuredHomeWidget(String title, String path, bool showDrawer) { + MaterialPageRoute configuredHomeWidget( + String title, String path, bool showDrawer) { return MaterialPageRoute(builder: (context) { return HomeScreen( - path: path, //"${server.domain}/apiv2/feeds/home", + path: path, showDrawer: showDrawer, title: title, isDarkMode: isDarkMode, @@ -75,21 +79,22 @@ class _MyAppState extends State { return configuredHomeWidget( 'Home', "${server.domain}/apiv2/feeds/home", true); } else if (settings.name == "/trending") { - return configuredHomeWidget( - 'Trending Content', "${server.domain}/apiv2/feeds/trending", true); + return configuredHomeWidget('Trending Content', + "${server.domain}/apiv2/feeds/trending", true); } else if (settings.name == "/new") { return configuredHomeWidget( 'New Content', "${server.domain}/apiv2/feeds/new", true); } else if (settings.name == "/firstUploads") { - return configuredHomeWidget( - 'First Uploads', "${server.domain}/apiv2/feeds/firstUploads", true); + return configuredHomeWidget('First Uploads', + "${server.domain}/apiv2/feeds/firstUploads", true); } else if (settings.name?.contains("/userChannel/") == true) { var last = settings.name?.split("/userChannel/").last ?? "threespeak"; return MaterialPageRoute(builder: (context) { return UserChannelScreen(owner: last); }); } else if (settings.name?.contains('/community/') == true) { - var last = settings.name?.split("/community/").last ?? "hive-167922?name=LeoFinance"; + var last = settings.name?.split("/community/").last ?? + "hive-167922?name=LeoFinance"; var comps = last.split("?name="); return MaterialPageRoute(builder: (context) { return CommunityDetailScreen(name: comps[0], title: comps[1]); diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index d338c115..55d5dc42 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -2,9 +2,11 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; +import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; +import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/video_player.dart'; import 'package:flutter/material.dart'; @@ -25,6 +27,8 @@ class VideoDetailsScreen extends StatefulWidget { } class _VideoDetailsScreenState extends State { + GlobalKey> key = GlobalKey>(); + void onUserTap() { Navigator.of(context).pushNamed("/userChannel/${widget.vm.author}"); } @@ -36,40 +40,72 @@ class _VideoDetailsScreenState extends State { } Widget descriptionMarkDown(String markDown) { - return Markdown( - data: Utilities.removeAllHtmlTags(markDown), - onTapLink: (text, url, title) { - launch(url!); - }, + var color = Theme.of(context).brightness == Brightness.dark + ? Colors.black87 + : Colors.white; + return Container( + decoration: BoxDecoration( + color: color, + ), + margin: const EdgeInsets.only(top: 60), + child: Markdown( + data: Utilities.removeAllHtmlTags(markDown), + onTapLink: (text, url, title) { + launch(url!); + }, + ), ); } - Widget titleAndSubtitle(VideoDetails details) { + Widget titleAndSubtitleCommon(VideoDetails details) { String string = "📆 ${timeago.format(DateTime.parse(details.created))} · ▶ ${details.views} views · 👥 ${details.community}"; - return InkWell( - child: Container( - margin: const EdgeInsets.all(10), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(details.title, - style: Theme.of(context).textTheme.bodyLarge), - const SizedBox(height: 3), - Text(string, style: Theme.of(context).textTheme.bodySmall), - ], - ), + return Container( + margin: const EdgeInsets.all(10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(details.title, + style: Theme.of(context).textTheme.bodyLarge), + const SizedBox(height: 3), + Text(string, style: Theme.of(context).textTheme.bodySmall), + ], ), - const Icon(Icons.keyboard_arrow_down_outlined), - ], - ), + ), + const Icon(Icons.arrow_drop_down_outlined), + ], ), + ); + } + + void showModal(VideoDetails details) { + showModalBottomSheet( + context: context, + builder: (context) { + return InkWell( + child: Stack( + children: [ + titleAndSubtitleCommon(details), + descriptionMarkDown( + "# ${details.owner}\n${details.description}"), + ], + ), + onTap: () { + Navigator.pop(context); + }, + ); + }); + } + + Widget titleAndSubtitle(VideoDetails details) { + return InkWell( + child: titleAndSubtitleCommon(details), onTap: () { - log('Hello'); + showModal(details); }, ); } @@ -77,17 +113,8 @@ class _VideoDetailsScreenState extends State { Widget listTile(HiveComment comment) { var item = comment; var userThumb = server.userOwnerThumb(item.author); - var author = item.author; var body = item.body; - var upVotes = item.activeVotes.where((e) => e.percent > 0).length; - var downVotes = item.activeVotes.where((e) => e.percent < 0).length; - var payout = item.pendingPayoutValue.replaceAll(" HBD", ""); - var timeInString = - item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; - var text = - "👤 $author 👍 $upVotes 👎 $downVotes 💰 $payout $timeInString"; - // var depth = (item.depth * 25.0) - 25; - double width = MediaQuery.of(context).size.width - 90; + double width = MediaQuery.of(context).size.width - 90 - 20; return Container( margin: const EdgeInsets.all(10), child: Row( @@ -97,25 +124,15 @@ class _VideoDetailsScreenState extends State { Container(margin: const EdgeInsets.only(right: 10)), SizedBox( width: width, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - MarkdownBody( - data: Utilities.removeAllHtmlTags(body), - shrinkWrap: true, - onTapLink: (text, url, title) { - launch(url!); - }, - ), - Container(margin: const EdgeInsets.only(bottom: 10)), - Text( - text, - style: Theme.of(context).textTheme.bodyText1, - ), - ], + child: MarkdownBody( + data: Utilities.removeAllHtmlTags(body), + shrinkWrap: true, + onTapLink: (text, url, title) { + launch(url!); + }, ), ), - const Icon(Icons.expand) + const Icon(Icons.arrow_drop_down_outlined) ], ), ); @@ -129,25 +146,44 @@ class _VideoDetailsScreenState extends State { ); } return InkWell( - child: listTile(comments.last), - onTap: () { - - }, + child: Container( + margin: const EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Comments ${comments.length}', + style: Theme.of(context).textTheme.bodyLarge), + listTile(comments.last) + ], + ), + ), + onTap: () {}, ); } Widget videoWithDetails(VideoDetails details) { - return ListView( - children: [ - SizedBox( - height: 230, - child: SPKVideoPlayer( - playUrl: details.playUrl, - ), - ), - titleAndSubtitle(details), - videoComments(), - ], + return ListView.separated( + itemBuilder: (context, index) { + if (index == 0) { + return SizedBox( + height: 230, + child: SPKVideoPlayer( + key: key, + playUrl: details.playUrl, + ), + ); + } else if (index == 1) { + return titleAndSubtitle(details); + } else if (index == 2) { + return videoComments(); + } else { + return ListTile( + title: videoRecommendationListItem(recommendations[index - 3]), + ); + } + }, + separatorBuilder: (context, index) => Container(), + itemCount: recommendations.length + 3, ); } @@ -158,12 +194,24 @@ class _VideoDetailsScreenState extends State { if (snapshot.hasError) { String text = 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; - return Container(margin: const EdgeInsets.all(10), child: Text(text)); + return Container( + margin: const EdgeInsets.all(10), child: Text(text)); } else if (snapshot.hasData) { var data = snapshot.data! as List; return commentsSection(data); } else { - return Container(margin: const EdgeInsets.all(10), child: const Text('Loading comments')); + return Container( + margin: const EdgeInsets.all(10), + child: Row( + children: const [ + SizedBox( + height: 15, + width: 15, + child: CircularProgressIndicator(value: null)), + SizedBox(width: 10), + Text('Loading comments') + ], + )); } }); } @@ -197,4 +245,39 @@ class _VideoDetailsScreenState extends State { }, ); } + + late Future> recommendedVideos; + List recommendations = []; + + @override + void initState() { + super.initState(); + widget.vm.getRecommendedVideos().then((value) { + setState(() { + recommendations = value; + }); + }); + } + + Widget videoRecommendationListItem(VideoRecommendationItem item) { + return ListTile( + title: ListTileVideo( + placeholder: 'assets/branding/three_speak_logo.png', + url: item.image, + userThumbUrl: server.userOwnerThumb(item.owner), + title: item.title, + subtitle: "", + onUserTap: () { + key.currentState?.widget.pauseVideo(); + // TO-DO - pause video before going to next screen + // Navigator.of(context).pushNamed("/userChannel/${item.owner}"); + }, + ), + onTap: () { + // TO-DO - pause video before going to next screen + // Navigator.of(context) + // .pushNamed(VideoDetailsScreen.routeName(item.owner, item.mediaid)); + }, + ); + } } diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index 7673bd24..bee199b9 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -11,6 +11,10 @@ class SPKVideoPlayer extends StatefulWidget { @override _SPKVideoPlayerState createState() => _SPKVideoPlayerState(); + + void pauseVideo() { + + } } class _SPKVideoPlayerState extends State diff --git a/pubspec.lock b/pubspec.lock index dfef7056..f3133bc9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "34.0.0" + version: "36.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "3.2.0" + version: "3.3.1" args: dependency: transitive description: @@ -120,13 +120,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.5" clock: dependency: transitive description: @@ -182,7 +175,7 @@ packages: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "2.2.2" fake_async: dependency: transitive description: @@ -210,21 +203,21 @@ packages: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "1.12.0" + version: "1.13.1" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "4.2.4" + version: "4.2.5" firebase_core_web: dependency: transitive description: name: firebase_core_web url: "https://pub.dartlang.org" source: hosted - version: "1.5.4" + version: "1.6.1" fixnum: dependency: transitive description: @@ -237,6 +230,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.2" flutter_lints: dependency: "direct dev" description: @@ -337,7 +337,7 @@ packages: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "6.1.4" + version: "6.1.5" lints: dependency: transitive description: @@ -435,7 +435,7 @@ packages: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" pubspec_parse: dependency: transitive description: @@ -636,7 +636,7 @@ packages: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.0.9" url_launcher_windows: dependency: transitive description: @@ -664,7 +664,7 @@ packages: name: video_player url: "https://pub.dartlang.org" source: hosted - version: "2.2.18" + version: "2.3.0" video_player_android: dependency: transitive description: @@ -706,7 +706,7 @@ packages: name: wakelock url: "https://pub.dartlang.org" source: hosted - version: "0.6.1+1" + version: "0.6.1+2" wakelock_macos: dependency: transitive description: @@ -764,5 +764,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.15.1 <3.0.0" + dart: ">=2.16.0 <3.0.0" flutter: ">=2.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index bfff74bb..e06478c3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,6 +31,7 @@ dependencies: firebase_core: ^1.12.0 flutter: sdk: flutter + flutter_dotenv: ^5.0.2 flutter_markdown: ^0.6.9 http: ^0.13.4 json_annotation: ^4.4.0 @@ -68,6 +69,7 @@ flutter: assets: - assets/branding/three_speak_logo.png - assets/branding/three_speak_icon.png + - .env # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg From 237fc0842586cd3c6a30c4def954ab6d4221c83e Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 9 Mar 2022 20:54:55 +0530 Subject: [PATCH 042/466] video details from bottom. --- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 8 ++++ .packages | 3 +- android/app/build.gradle | 1 - .../video_details_screen.dart | 38 +++++++++---------- pubspec.lock | 7 ++++ pubspec.yaml | 1 + 7 files changed, 37 insertions(+), 23 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index e6423ab2..0b882708 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-09 09:34:14.536418","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-09 20:41:20.591715","version":"2.10.3"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 1990b2ed..5c896455 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -37,6 +37,13 @@ + + + + + + @@ -780,6 +787,7 @@ + diff --git a/.packages b/.packages index 5697edb3..4809f03f 100644 --- a/.packages +++ b/.packages @@ -3,12 +3,13 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-03-09 07:00:46.405558. +# Generated by pub on 2022-03-09 20:16:36.379295. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ boolean_selector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/ +bottom_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/bottom_sheet-2.0.0/lib/ build:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build-2.2.1/lib/ build_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_config-1.0.0/lib/ build_daemon:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_daemon-3.0.1/lib/ diff --git a/android/app/build.gradle b/android/app/build.gradle index 0500500d..70df42e7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -43,7 +43,6 @@ android { } defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.acela" minSdkVersion flutter.minSdkVersion targetSdkVersion flutter.targetSdkVersion diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 55d5dc42..19fd91a6 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -13,6 +13,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:timeago/timeago.dart' as timeago; +import 'package:bottom_sheet/bottom_sheet.dart'; class VideoDetailsScreen extends StatefulWidget { const VideoDetailsScreen({Key? key, required this.vm}) : super(key: key); @@ -44,11 +45,8 @@ class _VideoDetailsScreenState extends State { ? Colors.black87 : Colors.white; return Container( - decoration: BoxDecoration( - color: color, - ), - margin: const EdgeInsets.only(top: 60), - child: Markdown( + margin: const EdgeInsets.all(10), + child: MarkdownBody( data: Utilities.removeAllHtmlTags(markDown), onTapLink: (text, url, title) { launch(url!); @@ -84,21 +82,21 @@ class _VideoDetailsScreenState extends State { void showModal(VideoDetails details) { showModalBottomSheet( - context: context, - builder: (context) { - return InkWell( - child: Stack( - children: [ - titleAndSubtitleCommon(details), - descriptionMarkDown( - "# ${details.owner}\n${details.description}"), - ], - ), - onTap: () { - Navigator.pop(context); - }, - ); - }); + context: context, + isScrollControlled: true, + clipBehavior: Clip.hardEdge, + builder: (context) { + return SizedBox( + height: MediaQuery.of(context).size.height-200.0, + child: ListView( + children: [ + titleAndSubtitleCommon(details), + descriptionMarkDown(details.description), + ], + ), + ); + }, + ); } Widget titleAndSubtitle(VideoDetails details) { diff --git a/pubspec.lock b/pubspec.lock index f3133bc9..10cb9e17 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -36,6 +36,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + bottom_sheet: + dependency: "direct main" + description: + name: bottom_sheet + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" build: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e06478c3..47d57358 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,6 +27,7 @@ environment: # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: + bottom_sheet: ^2.0.0 chewie: ^1.3.0 firebase_core: ^1.12.0 flutter: From 2b4ce4e4d2840357d9aa864d259fb299447f543f Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 10 Mar 2022 07:00:37 +0530 Subject: [PATCH 043/466] video details perfect scrolling. --- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 8 - .packages | 3 +- .../video_details_comments.dart | 61 +++---- .../video_details_recommendation.dart | 78 -------- .../video_details_screen.dart | 169 ++++++++++-------- .../video_details_tabbed_widget.dart | 86 --------- lib/src/widgets/video_player.dart | 12 +- pubspec.lock | 7 - pubspec.yaml | 1 - 10 files changed, 118 insertions(+), 309 deletions(-) delete mode 100644 lib/src/screens/video_details_screen/video_details_recommendation.dart delete mode 100644 lib/src/screens/video_details_screen/video_details_tabbed_widget.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 0b882708..3bf03012 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-09 20:41:20.591715","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-10 06:53:50.181927","version":"2.10.3"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 5c896455..1990b2ed 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -37,13 +37,6 @@ - - - - - - @@ -787,7 +780,6 @@ - diff --git a/.packages b/.packages index 4809f03f..c4b6bf53 100644 --- a/.packages +++ b/.packages @@ -3,13 +3,12 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-03-09 20:16:36.379295. +# Generated by pub on 2022-03-10 06:28:17.618192. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ boolean_selector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/ -bottom_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/bottom_sheet-2.0.0/lib/ build:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build-2.2.1/lib/ build_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_config-1.0.0/lib/ build_daemon:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_daemon-3.0.1/lib/ diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart index f236f43e..ff4c1f0c 100644 --- a/lib/src/screens/video_details_screen/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -1,31 +1,17 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; -import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:timeago/timeago.dart' as timeago; import 'package:url_launcher/url_launcher.dart'; -class VideoDetailsCommentsWidget extends StatefulWidget { - const VideoDetailsCommentsWidget( - {Key? key, required this.vm}) - : super(key: key); - final VideoDetailsViewModel vm; +class VideoDetailsComments extends StatelessWidget { + const VideoDetailsComments({Key? key, required this.data}) : super(key: key); + final List data; - @override - _VideoDetailsCommentsWidgetState createState() => - _VideoDetailsCommentsWidgetState(); -} - -class _VideoDetailsCommentsWidgetState extends State - with AutomaticKeepAliveClientMixin { - @override - bool get wantKeepAlive => true; - - Widget listTile(HiveComment comment) { + Widget listTile(HiveComment comment, BuildContext context) { var item = comment; var userThumb = server.userOwnerThumb(item.author); var author = item.author; @@ -34,7 +20,7 @@ class _VideoDetailsCommentsWidgetState extends State var downVotes = item.activeVotes.where((e) => e.percent < 0).length; var payout = item.pendingPayoutValue.replaceAll(" HBD", ""); var timeInString = - item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; + item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; var text = "👤 $author 👍 $upVotes 👎 $downVotes 💰 $payout $timeInString"; var depth = (item.depth * 25.0) - 25; @@ -74,37 +60,30 @@ class _VideoDetailsCommentsWidgetState extends State ); } - Widget commentsListView(List comments) { + Widget commentsListView(BuildContext context) { return Container( margin: const EdgeInsets.only(top: 10, bottom: 10), child: ListView.separated( itemBuilder: (context, index) { - return listTile(comments[index]); + if (index == 0) { + return Container( + margin: const EdgeInsets.only(left: 10, right: 10), + child: Text('Comments', style: Theme.of(context).textTheme.bodyLarge), + ); + } else { + return listTile(data[index - 1], context); + } }, separatorBuilder: (context, index) => const Divider( - height: 10, - color: Colors.blueGrey, - ), - itemCount: comments.length), + height: 10, + color: Colors.blueGrey, + ), + itemCount: data.length + 1), ); } @override Widget build(BuildContext context) { - super.build(context); - return FutureBuilder( - future: widget.vm.loadComments(widget.vm.author, widget.vm.permlink), - builder: (builder, snapshot) { - if (snapshot.hasError) { - String text = - 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; - return Text(text); - } else if (snapshot.hasData) { - var data = snapshot.data! as List; - return commentsListView(data); - } else { - return const LoadingScreen(); - } - }); + return commentsListView(context); } -} +} \ No newline at end of file diff --git a/lib/src/screens/video_details_screen/video_details_recommendation.dart b/lib/src/screens/video_details_screen/video_details_recommendation.dart deleted file mode 100644 index 4a3a1614..00000000 --- a/lib/src/screens/video_details_screen/video_details_recommendation.dart +++ /dev/null @@ -1,78 +0,0 @@ -import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; -import 'package:acela/src/widgets/list_tile_video.dart'; -import 'package:acela/src/widgets/loading_screen.dart'; -import 'package:flutter/material.dart'; - -class VideoDetailsRecommendationWidget extends StatefulWidget { - const VideoDetailsRecommendationWidget({Key? key, required this.vm}) - : super(key: key); - final VideoDetailsViewModel vm; - - @override - _VideoDetailsRecommendationWidgetState createState() => - _VideoDetailsRecommendationWidgetState(); -} - -class _VideoDetailsRecommendationWidgetState - extends State - with AutomaticKeepAliveClientMixin { - @override - bool get wantKeepAlive => true; - - Widget listTile(VideoRecommendationItem item) { - return ListTile( - title: ListTileVideo( - placeholder: 'assets/branding/three_speak_logo.png', - url: item.image, - userThumbUrl: server.userOwnerThumb(item.owner), - title: item.title, - subtitle: "", - onUserTap: () { - Navigator.of(context).pushNamed("/userChannel/${item.owner}"); - }, - ), - onTap: () { - Navigator.of(context) - .pushNamed(VideoDetailsScreen.routeName(item.owner, item.mediaid)); - }, - ); - } - - Widget recommendationsListView(List videos) { - return Container( - margin: const EdgeInsets.only(top: 10, bottom: 10), - child: ListView.separated( - itemBuilder: (context, index) { - return listTile(videos[index]); - }, - separatorBuilder: (context, index) => const Divider( - height: 10, - color: Colors.blueGrey, - ), - itemCount: videos.length), - ); - } - - @override - Widget build(BuildContext context) { - super.build(context); - return FutureBuilder( - future: widget.vm.getRecommendedVideos(), - builder: (builder, snapshot) { - if (snapshot.hasError) { - String text = - 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; - return Text(text); - } else if (snapshot.hasData) { - var data = snapshot.data! as List; - return recommendationsListView(data); - } else { - return const LoadingScreen(); - } - }, - ); - } -} diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 19fd91a6..82d931b8 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -3,6 +3,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; @@ -13,7 +14,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:timeago/timeago.dart' as timeago; -import 'package:bottom_sheet/bottom_sheet.dart'; class VideoDetailsScreen extends StatefulWidget { const VideoDetailsScreen({Key? key, required this.vm}) : super(key: key); @@ -28,22 +28,38 @@ class VideoDetailsScreen extends StatefulWidget { } class _VideoDetailsScreenState extends State { - GlobalKey> key = GlobalKey>(); + late Future> recommendedVideos; + List recommendations = []; + late Future> _loadComments; + + @override + void initState() { + super.initState(); + widget.vm.getRecommendedVideos().then((value) { + setState(() { + recommendations = value; + }); + }); + _loadComments = + widget.vm.loadComments(widget.vm.author, widget.vm.permlink); + } void onUserTap() { Navigator.of(context).pushNamed("/userChannel/${widget.vm.author}"); } + // used when there is an error state in loading video info Widget container(String title, Widget body) { return Scaffold( body: body, + appBar: AppBar( + title: Text(title), + ), ); } + // video description Widget descriptionMarkDown(String markDown) { - var color = Theme.of(context).brightness == Brightness.dark - ? Colors.black87 - : Colors.white; return Container( margin: const EdgeInsets.all(10), child: MarkdownBody( @@ -55,6 +71,7 @@ class _VideoDetailsScreenState extends State { ); } + // video description Widget titleAndSubtitleCommon(VideoDetails details) { String string = "📆 ${timeago.format(DateTime.parse(details.created))} · ▶ ${details.views} views · 👥 ${details.community}"; @@ -80,14 +97,15 @@ class _VideoDetailsScreenState extends State { ); } - void showModal(VideoDetails details) { + // video description + void showModalForDescription(VideoDetails details) { showModalBottomSheet( context: context, isScrollControlled: true, clipBehavior: Clip.hardEdge, builder: (context) { return SizedBox( - height: MediaQuery.of(context).size.height-200.0, + height: MediaQuery.of(context).size.height - 200.0, child: ListView( children: [ titleAndSubtitleCommon(details), @@ -99,15 +117,17 @@ class _VideoDetailsScreenState extends State { ); } + // video description Widget titleAndSubtitle(VideoDetails details) { return InkWell( child: titleAndSubtitleCommon(details), onTap: () { - showModal(details); + showModalForDescription(details); }, ); } + // video comments Widget listTile(HiveComment comment) { var item = comment; var userThumb = server.userOwnerThumb(item.author); @@ -136,6 +156,7 @@ class _VideoDetailsScreenState extends State { ); } + // video comments Widget commentsSection(List comments) { if (comments.isEmpty) { return Container( @@ -155,43 +176,30 @@ class _VideoDetailsScreenState extends State { ], ), ), - onTap: () {}, - ); - } - - Widget videoWithDetails(VideoDetails details) { - return ListView.separated( - itemBuilder: (context, index) { - if (index == 0) { - return SizedBox( - height: 230, - child: SPKVideoPlayer( - key: key, - playUrl: details.playUrl, - ), - ); - } else if (index == 1) { - return titleAndSubtitle(details); - } else if (index == 2) { - return videoComments(); - } else { - return ListTile( - title: videoRecommendationListItem(recommendations[index - 3]), - ); - } + onTap: () { + showModalBottomSheet( + context: context, + isScrollControlled: true, + clipBehavior: Clip.hardEdge, + builder: (context) { + return SizedBox( + height: MediaQuery.of(context).size.height - 200.0, + child: VideoDetailsComments(data: comments), + ); + }, + ); }, - separatorBuilder: (context, index) => Container(), - itemCount: recommendations.length + 3, ); } + // video comments Widget videoComments() { return FutureBuilder( - future: widget.vm.loadComments(widget.vm.author, widget.vm.permlink), + future: _loadComments, builder: (builder, snapshot) { if (snapshot.hasError) { String text = - 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; + 'Something went wrong while loading video comments - ${snapshot.error?.toString() ?? ""}'; return Container( margin: const EdgeInsets.all(10), child: Text(text)); } else if (snapshot.hasData) { @@ -214,6 +222,44 @@ class _VideoDetailsScreenState extends State { }); } + // container list view + Widget videoWithDetails(VideoDetails details) { + return Container( + margin: const EdgeInsets.only(top: 230), + child: ListView.separated( + itemBuilder: (context, index) { + if (index == 0) { + return titleAndSubtitle(details); + } else if (index == 1) { + return videoComments(); + } else { + return ListTile( + title: videoRecommendationListItem(recommendations[index - 2]), + ); + } + }, + separatorBuilder: (context, index) => Container(), + itemCount: recommendations.length + 2, + ), + ); + } + + // container list view - recommendations + Widget videoRecommendationListItem(VideoRecommendationItem item) { + return ListTileVideo( + placeholder: 'assets/branding/three_speak_logo.png', + url: item.image, + userThumbUrl: server.userOwnerThumb(item.owner), + title: item.title, + subtitle: "", + onUserTap: () { + // TO-DO - pause video before going to next screen + Navigator.of(context).pushNamed("/userChannel/${item.owner}"); + }, + ); + } + + // main container @override Widget build(BuildContext context) { return FutureBuilder( @@ -221,20 +267,30 @@ class _VideoDetailsScreenState extends State { builder: (builder, snapshot) { if (snapshot.hasError) { String text = - 'Something went wrong - ${snapshot.error?.toString() ?? ""}'; + 'Something went wrong while loading video information - ${snapshot.error?.toString() ?? ""}'; return container(widget.vm.author, Text(text)); } else if (snapshot.hasData) { var data = snapshot.data as VideoDetails?; if (data != null) { return Scaffold( body: SafeArea( - child: videoWithDetails(data), + child: Stack( + children: [ + videoWithDetails(data), + SizedBox( + height: 230, + child: SPKVideoPlayer( + playUrl: data.playUrl, + ), + ), + ], + ) ), ); } else { return container( widget.vm.author, - const Text("Something went wrong"), + const Text("Something went wrong while loading video information"), ); } } else { @@ -243,39 +299,4 @@ class _VideoDetailsScreenState extends State { }, ); } - - late Future> recommendedVideos; - List recommendations = []; - - @override - void initState() { - super.initState(); - widget.vm.getRecommendedVideos().then((value) { - setState(() { - recommendations = value; - }); - }); - } - - Widget videoRecommendationListItem(VideoRecommendationItem item) { - return ListTile( - title: ListTileVideo( - placeholder: 'assets/branding/three_speak_logo.png', - url: item.image, - userThumbUrl: server.userOwnerThumb(item.owner), - title: item.title, - subtitle: "", - onUserTap: () { - key.currentState?.widget.pauseVideo(); - // TO-DO - pause video before going to next screen - // Navigator.of(context).pushNamed("/userChannel/${item.owner}"); - }, - ), - onTap: () { - // TO-DO - pause video before going to next screen - // Navigator.of(context) - // .pushNamed(VideoDetailsScreen.routeName(item.owner, item.mediaid)); - }, - ); - } } diff --git a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart b/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart deleted file mode 100644 index ac20548d..00000000 --- a/lib/src/screens/video_details_screen/video_details_tabbed_widget.dart +++ /dev/null @@ -1,86 +0,0 @@ -import 'package:flutter/material.dart'; -import 'dart:io' show Platform; -import 'package:share_plus/share_plus.dart'; - -class VideoDetailsTabbedWidget extends StatefulWidget { - const VideoDetailsTabbedWidget( - {Key? key, - required this.children, - required this.title, - required this.onUserTap, - required this.fullscreen, - required this.routeName}) - : super(key: key); - final List children; - final String title; - final Function onUserTap; - final bool fullscreen; - final String routeName; - - @override - _VideoDetailsTabbedWidgetState createState() => - _VideoDetailsTabbedWidgetState(); -} - -class _VideoDetailsTabbedWidgetState extends State - with SingleTickerProviderStateMixin { - static const List tabs = [ - Tab(text: 'Description'), - Tab(text: 'Comments'), - Tab(text: 'Recommendation'), - ]; - - late TabController _tabController; - - @override - void initState() { - super.initState(); - _tabController = TabController(vsync: this, length: tabs.length); - } - - @override - void dispose() { - _tabController.dispose(); - super.dispose(); - } - - List _buttons() { - var channelButton = IconButton( - onPressed: () { - widget.onUserTap(); - }, - icon: const Icon(Icons.person), - ); - var shareButton = IconButton( - onPressed: () { - Share.share( - widget.routeName, - subject: 'I found this video interesting ${widget.routeName}', - ); - }, - icon: const Icon(Icons.share), - ); - if (Platform.isAndroid || Platform.isIOS) { - return [channelButton, shareButton]; - } else { - return [channelButton]; - } - } - - @override - Widget build(BuildContext context) { - return Column( - children: [ - TabBar( - controller: _tabController, - isScrollable: true, - tabs: tabs, - ), - TabBarView( - controller: _tabController, - children: widget.children, - ), - ], - ); - } -} diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index bee199b9..c40dbdd6 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -11,21 +11,12 @@ class SPKVideoPlayer extends StatefulWidget { @override _SPKVideoPlayerState createState() => _SPKVideoPlayerState(); - - void pauseVideo() { - - } } -class _SPKVideoPlayerState extends State - with AutomaticKeepAliveClientMixin { - +class _SPKVideoPlayerState extends State { late VideoPlayerController videoPlayerController; ChewieController? chewieController; - @override - bool get wantKeepAlive => true; - @override void dispose() { super.dispose(); @@ -50,7 +41,6 @@ class _SPKVideoPlayerState extends State @override Widget build(BuildContext context) { - super.build(context); return chewieController == null ? const LoadingScreen() : Chewie(controller: chewieController!); diff --git a/pubspec.lock b/pubspec.lock index 10cb9e17..f3133bc9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -36,13 +36,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" - bottom_sheet: - dependency: "direct main" - description: - name: bottom_sheet - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" build: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 47d57358..e06478c3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,6 @@ environment: # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: - bottom_sheet: ^2.0.0 chewie: ^1.3.0 firebase_core: ^1.12.0 flutter: From 0512bb9413b1c15ed1c8ae3ce0511f9e14a6d00b Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 10 Mar 2022 14:50:28 +0530 Subject: [PATCH 044/466] video details to full screen video details. --- .flutter-plugins-dependencies | 2 +- .packages | 2 +- lib/src/bloc/server.dart | 1 + .../video_details_info.dart | 60 ++++++++++ .../video_details_screen.dart | 112 +++++++++++------- lib/src/widgets/video_player.dart | 2 +- pubspec.lock | 2 +- pubspec.yaml | 1 + 8 files changed, 135 insertions(+), 47 deletions(-) create mode 100644 lib/src/screens/video_details_screen/video_details_info.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 3bf03012..e62dc565 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-10 06:53:50.181927","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-10 14:14:38.604691","version":"2.10.3"} \ No newline at end of file diff --git a/.packages b/.packages index c4b6bf53..50855a8e 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-03-10 06:28:17.618192. +# Generated by pub on 2022-03-10 09:39:27.123034. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ diff --git a/lib/src/bloc/server.dart b/lib/src/bloc/server.dart index 69981ddc..1caba343 100644 --- a/lib/src/bloc/server.dart +++ b/lib/src/bloc/server.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:developer'; class Server { diff --git a/lib/src/screens/video_details_screen/video_details_info.dart b/lib/src/screens/video_details_screen/video_details_info.dart new file mode 100644 index 00000000..c14d0d63 --- /dev/null +++ b/lib/src/screens/video_details_screen/video_details_info.dart @@ -0,0 +1,60 @@ +import 'package:acela/src/models/video_details_model/video_details.dart'; +import 'package:acela/src/utils/seconds_to_duration.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:timeago/timeago.dart' as timeago; + +class VideoDetailsInfoWidget extends StatelessWidget { + const VideoDetailsInfoWidget({Key? key, required this.details}) : super(key: key); + final VideoDetails details; + + Widget header(BuildContext context) { + String string = + "📆 ${timeago.format(DateTime.parse(details.created))} · ▶ ${details.views} views · 👥 ${details.community}"; + return Container( + margin: const EdgeInsets.only(left: 10, right: 10, top: 10), + child: Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(details.title, + style: Theme.of(context).textTheme.bodyLarge), + const SizedBox(height: 3), + Text(string, style: Theme.of(context).textTheme.bodySmall), + ], + ), + ), + ); + } + + Widget descriptionMarkDown(String markDown) { + return Markdown( + padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10), + data: Utilities.removeAllHtmlTags(markDown), + onTapLink: (text, url, title) { + launch(url!); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(details.owner), + ), + body: SafeArea( + child: Stack( + children: [ + Container( + margin: const EdgeInsets.only(top: 70), + child: descriptionMarkDown(details.description), + ), + header(context), + ], + ), + ), + ); + } +} diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 82d931b8..7eeb4fbe 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -4,6 +4,7 @@ import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_info.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; @@ -58,41 +59,60 @@ class _VideoDetailsScreenState extends State { ); } + //region Video Info // video description Widget descriptionMarkDown(String markDown) { - return Container( - margin: const EdgeInsets.all(10), - child: MarkdownBody( - data: Utilities.removeAllHtmlTags(markDown), - onTapLink: (text, url, title) { - launch(url!); - }, - ), + return Markdown( + data: Utilities.removeAllHtmlTags(markDown), + onTapLink: (text, url, title) { + launch(url!); + }, ); } // video description - Widget titleAndSubtitleCommon(VideoDetails details) { + Widget titleAndSubtitleCommon(VideoDetails details, bool fullScreen) { String string = "📆 ${timeago.format(DateTime.parse(details.created))} · ▶ ${details.views} views · 👥 ${details.community}"; + var fullScreenButton = IconButton( + onPressed: () { + var route = MaterialPageRoute(builder: (context) { + return VideoDetailsInfoWidget(details: details); + }); + Navigator.of(context).push(route); + }, + icon: const Icon(Icons.fullscreen), + ); + var closeButton = IconButton( + onPressed: () { + Navigator.of(context).pop(); + }, + icon: const Icon(Icons.close), + ); + var downIcon = const Icon(Icons.arrow_drop_down_outlined); + List children = [ + Expanded( + child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(details.title, style: Theme.of(context).textTheme.bodyLarge), + const SizedBox(height: 3), + Text(string, style: Theme.of(context).textTheme.bodySmall), + ], + ), + ), + ]; + if (fullScreen) { + children.add(fullScreenButton); + children.add(closeButton); + } else { + children.add(downIcon); + } return Container( margin: const EdgeInsets.all(10), child: Row( crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(details.title, - style: Theme.of(context).textTheme.bodyLarge), - const SizedBox(height: 3), - Text(string, style: Theme.of(context).textTheme.bodySmall), - ], - ), - ), - const Icon(Icons.arrow_drop_down_outlined), - ], + children: children, ), ); } @@ -105,11 +125,14 @@ class _VideoDetailsScreenState extends State { clipBehavior: Clip.hardEdge, builder: (context) { return SizedBox( - height: MediaQuery.of(context).size.height - 200.0, - child: ListView( + height: MediaQuery.of(context).size.height - 230.0, + child: Stack( children: [ - titleAndSubtitleCommon(details), - descriptionMarkDown(details.description), + Container( + margin: const EdgeInsets.only(top: 70), + child: descriptionMarkDown(details.description), + ), + titleAndSubtitleCommon(details, true), ], ), ); @@ -120,13 +143,16 @@ class _VideoDetailsScreenState extends State { // video description Widget titleAndSubtitle(VideoDetails details) { return InkWell( - child: titleAndSubtitleCommon(details), + child: titleAndSubtitleCommon(details, false), onTap: () { showModalForDescription(details); }, ); } + //endregion + + //region Video Comments // video comments Widget listTile(HiveComment comment) { var item = comment; @@ -183,7 +209,7 @@ class _VideoDetailsScreenState extends State { clipBehavior: Clip.hardEdge, builder: (context) { return SizedBox( - height: MediaQuery.of(context).size.height - 200.0, + height: MediaQuery.of(context).size.height - 230.0, child: VideoDetailsComments(data: comments), ); }, @@ -222,6 +248,7 @@ class _VideoDetailsScreenState extends State { }); } + //endregion // container list view Widget videoWithDetails(VideoDetails details) { return Container( @@ -251,9 +278,8 @@ class _VideoDetailsScreenState extends State { url: item.image, userThumbUrl: server.userOwnerThumb(item.owner), title: item.title, - subtitle: "", + subtitle: "👤 ${item.owner}", onUserTap: () { - // TO-DO - pause video before going to next screen Navigator.of(context).pushNamed("/userChannel/${item.owner}"); }, ); @@ -274,23 +300,23 @@ class _VideoDetailsScreenState extends State { if (data != null) { return Scaffold( body: SafeArea( - child: Stack( - children: [ - videoWithDetails(data), - SizedBox( - height: 230, - child: SPKVideoPlayer( - playUrl: data.playUrl, - ), + child: Stack( + children: [ + videoWithDetails(data), + SizedBox( + height: 230, + child: SPKVideoPlayer( + playUrl: data.playUrl, ), - ], - ) - ), + ), + ], + )), ); } else { return container( widget.vm.author, - const Text("Something went wrong while loading video information"), + const Text( + "Something went wrong while loading video information"), ); } } else { diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index c40dbdd6..8be040f6 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -26,7 +26,7 @@ class _SPKVideoPlayerState extends State { @override void initState() { videoPlayerController = VideoPlayerController.network(widget.playUrl, - videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true)) + videoPlayerOptions: VideoPlayerOptions(allowBackgroundPlayback: true)) ..initialize().then((_) { setState(() { chewieController = ChewieController( diff --git a/pubspec.lock b/pubspec.lock index f3133bc9..2a5636fe 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -423,7 +423,7 @@ packages: source: hosted version: "1.5.0" provider: - dependency: transitive + dependency: "direct main" description: name: provider url: "https://pub.dartlang.org" diff --git a/pubspec.yaml b/pubspec.yaml index e06478c3..469410b1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,6 +35,7 @@ dependencies: flutter_markdown: ^0.6.9 http: ^0.13.4 json_annotation: ^4.4.0 + provider: ^6.0.2 share_plus: ^3.1.0 timeago: ^3.1.0 url_launcher: ^6.0.20 From 84d18288f9abddac5e907ee55a4c7417de4d446b Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 11 Mar 2022 07:14:31 +0530 Subject: [PATCH 045/466] comments re-written. --- .flutter-plugins-dependencies | 2 +- .../video_details_comments.dart | 107 ++++++++++++++---- .../video_details_screen.dart | 85 +++++++------- .../video_details_view_model.dart | 14 +++ 4 files changed, 144 insertions(+), 64 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index e62dc565..0cd10387 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-10 14:14:38.604691","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-11 06:48:54.026695","version":"2.10.3"} \ No newline at end of file diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart index ff4c1f0c..09c15fe4 100644 --- a/lib/src/screens/video_details_screen/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -1,4 +1,5 @@ import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; @@ -6,12 +7,54 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:timeago/timeago.dart' as timeago; import 'package:url_launcher/url_launcher.dart'; +import 'package:http/http.dart' as http; -class VideoDetailsComments extends StatelessWidget { - const VideoDetailsComments({Key? key, required this.data}) : super(key: key); - final List data; +class VideoDetailsComments extends StatefulWidget { + const VideoDetailsComments( + {Key? key, required this.author, required this.permlink}) + : super(key: key); + final String author; + final String permlink; - Widget listTile(HiveComment comment, BuildContext context) { + @override + State createState() => _VideoDetailsCommentsState(); +} + +class _VideoDetailsCommentsState extends State { + late Future> _loadComments; + + Future> loadComments(String author, String permlink) async { + var client = http.Client(); + var body = + hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); + var response = await client.post(Uri.parse(server.hiveDomain), body: body); + if (response.statusCode == 200) { + var hiveCommentsResponse = hiveCommentsFromString(response.body); + var comments = hiveCommentsResponse.result; + for (var i = 0; i < comments.length; i++) { + if (comments[i].children > 0) { + if (comments + .where((e) => e.parentPermlink == comments[i].permlink) + .isEmpty) { + var newComments = + await loadComments(comments[i].author, comments[i].permlink); + comments.insertAll(i + 1, newComments); + } + } + } + return comments; + } else { + throw "Status code is ${response.statusCode}"; + } + } + + @override + void initState() { + super.initState(); + _loadComments = loadComments(widget.author, widget.permlink); + } + + Widget listTile(HiveComment comment) { var item = comment; var userThumb = server.userOwnerThumb(item.author); var author = item.author; @@ -20,7 +63,7 @@ class VideoDetailsComments extends StatelessWidget { var downVotes = item.activeVotes.where((e) => e.percent < 0).length; var payout = item.pendingPayoutValue.replaceAll(" HBD", ""); var timeInString = - item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; + item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; var text = "👤 $author 👍 $upVotes 👎 $downVotes 💰 $payout $timeInString"; var depth = (item.depth * 25.0) - 25; @@ -60,30 +103,54 @@ class VideoDetailsComments extends StatelessWidget { ); } - Widget commentsListView(BuildContext context) { + Widget commentsListView(List data) { return Container( margin: const EdgeInsets.only(top: 10, bottom: 10), child: ListView.separated( itemBuilder: (context, index) { - if (index == 0) { - return Container( - margin: const EdgeInsets.only(left: 10, right: 10), - child: Text('Comments', style: Theme.of(context).textTheme.bodyLarge), - ); - } else { - return listTile(data[index - 1], context); - } + return listTile(data[index]); }, separatorBuilder: (context, index) => const Divider( - height: 10, - color: Colors.blueGrey, - ), - itemCount: data.length + 1), + height: 10, + color: Colors.blueGrey, + ), + itemCount: data.length), ); } @override Widget build(BuildContext context) { - return commentsListView(context); + return Scaffold( + appBar: AppBar( + title: const Text('Comments'), + ), + body: FutureBuilder( + future: _loadComments, + builder: (builder, snapshot) { + if (snapshot.hasError) { + String text = + 'Something went wrong while loading video comments - ${snapshot.error?.toString() ?? ""}'; + return Container( + margin: const EdgeInsets.all(10), child: Text(text)); + } else if (snapshot.hasData) { + var data = snapshot.data! as List; + return commentsListView(data); + } else { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + Spacer(), + SizedBox(child: CircularProgressIndicator(value: null)), + SizedBox(height: 10), + Text('Loading comments'), + Spacer(), + ], + ), + ); + } + }, + ), + ); } -} \ No newline at end of file +} diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 7eeb4fbe..3056a57c 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -42,7 +42,7 @@ class _VideoDetailsScreenState extends State { }); }); _loadComments = - widget.vm.loadComments(widget.vm.author, widget.vm.permlink); + widget.vm.loadFirstSetOfComments(widget.vm.author, widget.vm.permlink); } void onUserTap() { @@ -169,14 +169,17 @@ class _VideoDetailsScreenState extends State { SizedBox( width: width, child: MarkdownBody( - data: Utilities.removeAllHtmlTags(body), + data: Utilities.removeAllHtmlTags(body) + .split('') + .take(100) + .join(''), shrinkWrap: true, onTapLink: (text, url, title) { launch(url!); }, ), ), - const Icon(Icons.arrow_drop_down_outlined) + const Icon(Icons.arrow_right_outlined) ], ), ); @@ -192,28 +195,20 @@ class _VideoDetailsScreenState extends State { } return InkWell( child: Container( - margin: const EdgeInsets.all(10), + margin: const EdgeInsets.only(left: 10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Comments ${comments.length}', - style: Theme.of(context).textTheme.bodyLarge), + Text('Comments :', style: Theme.of(context).textTheme.bodyLarge), listTile(comments.last) ], ), ), onTap: () { - showModalBottomSheet( - context: context, - isScrollControlled: true, - clipBehavior: Clip.hardEdge, - builder: (context) { - return SizedBox( - height: MediaQuery.of(context).size.height - 230.0, - child: VideoDetailsComments(data: comments), - ); - }, - ); + Navigator.of(context).push(MaterialPageRoute(builder: (context) { + return VideoDetailsComments( + author: widget.vm.author, permlink: widget.vm.permlink); + })); }, ); } @@ -221,31 +216,31 @@ class _VideoDetailsScreenState extends State { // video comments Widget videoComments() { return FutureBuilder( - future: _loadComments, - builder: (builder, snapshot) { - if (snapshot.hasError) { - String text = - 'Something went wrong while loading video comments - ${snapshot.error?.toString() ?? ""}'; - return Container( - margin: const EdgeInsets.all(10), child: Text(text)); - } else if (snapshot.hasData) { - var data = snapshot.data! as List; - return commentsSection(data); - } else { - return Container( - margin: const EdgeInsets.all(10), - child: Row( - children: const [ - SizedBox( - height: 15, - width: 15, - child: CircularProgressIndicator(value: null)), - SizedBox(width: 10), - Text('Loading comments') - ], - )); - } - }); + future: _loadComments, + builder: (builder, snapshot) { + if (snapshot.hasError) { + String text = + 'Something went wrong while loading video comments - ${snapshot.error?.toString() ?? ""}'; + return Container(margin: const EdgeInsets.all(10), child: Text(text)); + } else if (snapshot.hasData) { + var data = snapshot.data! as List; + return commentsSection(data); + } else { + return Container( + margin: const EdgeInsets.all(10), + child: Row( + children: const [ + SizedBox( + height: 15, + width: 15, + child: CircularProgressIndicator(value: null)), + SizedBox(width: 10), + Text('Loading comments') + ], + )); + } + }, + ); } //endregion @@ -259,9 +254,13 @@ class _VideoDetailsScreenState extends State { return titleAndSubtitle(details); } else if (index == 1) { return videoComments(); + } else if (index == 2) { + return const ListTile( + title: Text('Recommended Videos'), + ); } else { return ListTile( - title: videoRecommendationListItem(recommendations[index - 2]), + title: videoRecommendationListItem(recommendations[index - 3]), ); } }, diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index 4e85cc7b..4c412273 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -96,4 +96,18 @@ class VideoDetailsViewModel { throw "Status code is ${response.statusCode}"; } } + + Future> loadFirstSetOfComments(String author, String permlink) async { + var client = http.Client(); + var body = + hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); + var response = await client.post(Uri.parse(server.hiveDomain), body: body); + if (response.statusCode == 200) { + var hiveCommentsResponse = hiveCommentsFromString(response.body); + var comments = hiveCommentsResponse.result; + return comments; + } else { + throw "Status code is ${response.statusCode}"; + } + } } From 69baeaffc03d33b7f1345ee38277bacec10030ca Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 11 Mar 2022 18:38:00 +0530 Subject: [PATCH 046/466] Fixed routes. instead of using named routes, switching to material page routes. --- .flutter-plugins-dependencies | 2 +- lib/main.dart | 113 +++++++----------- .../communities_screen.dart | 6 +- .../community_details_screen.dart | 11 +- .../screens/drawer_screen/drawer_screen.dart | 57 +++++---- lib/src/screens/home_screen/home_screen.dart | 83 ++++++++----- .../leaderboard_screen.dart | 4 +- .../user_channel_videos.dart | 8 +- .../video_details_screen.dart | 12 +- .../video_details_view_model.dart | 37 +----- 10 files changed, 158 insertions(+), 175 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 0cd10387..d41f6bc1 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-11 06:48:54.026695","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-11 18:30:56.262624","version":"2.10.3"} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 506d445f..562dd7d1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,17 +1,9 @@ -import 'package:acela/src/screens/communities_screen/communities_screen.dart'; -import 'package:acela/src/screens/communities_screen/community_details/community_details_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; -import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; -import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'firebase_options.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'src/bloc/server.dart'; - Future main() async { await dotenv.load(fileName: ".env"); WidgetsFlutterBinding.ensureInitialized(); @@ -28,7 +20,6 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { final Future _fbApp = Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); - bool isDarkMode = true; Widget futureBuilder(Widget withWidget) { return FutureBuilder( @@ -45,72 +36,56 @@ class _MyAppState extends State { ); } - MaterialPageRoute configuredHomeWidget( - String title, String path, bool showDrawer) { - return MaterialPageRoute(builder: (context) { - return HomeScreen( - path: path, - showDrawer: showDrawer, - title: title, - isDarkMode: isDarkMode, - switchDarkMode: () { - setState(() { - isDarkMode = !isDarkMode; - }); - }, - ); - }); - } - // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Acela - 3Speak App', - theme: isDarkMode ? ThemeData.dark() : ThemeData.light(), + home: HomeScreen.home(), debugShowCheckedModeBanner: false, - onGenerateRoute: (settings) { - if (settings.name?.contains("/watch?") == true) { - return MaterialPageRoute(builder: (context) { - return VideoDetailsScreen( - vm: VideoDetailsViewModel.from(settings.name!)); - }); - } else if (settings.name == "/") { - return configuredHomeWidget( - 'Home', "${server.domain}/apiv2/feeds/home", true); - } else if (settings.name == "/trending") { - return configuredHomeWidget('Trending Content', - "${server.domain}/apiv2/feeds/trending", true); - } else if (settings.name == "/new") { - return configuredHomeWidget( - 'New Content', "${server.domain}/apiv2/feeds/new", true); - } else if (settings.name == "/firstUploads") { - return configuredHomeWidget('First Uploads', - "${server.domain}/apiv2/feeds/firstUploads", true); - } else if (settings.name?.contains("/userChannel/") == true) { - var last = settings.name?.split("/userChannel/").last ?? "threespeak"; - return MaterialPageRoute(builder: (context) { - return UserChannelScreen(owner: last); - }); - } else if (settings.name?.contains('/community/') == true) { - var last = settings.name?.split("/community/").last ?? - "hive-167922?name=LeoFinance"; - var comps = last.split("?name="); - return MaterialPageRoute(builder: (context) { - return CommunityDetailScreen(name: comps[0], title: comps[1]); - }); - } else if (settings.name == "/leaderboard") { - return MaterialPageRoute(builder: (context) { - return const LeaderboardScreen(); - }); - } else if (settings.name == "/communities") { - return MaterialPageRoute(builder: (context) { - return const CommunitiesScreen(); - }); - } - assert(false, 'Need to implement ${settings.name}'); - return null; - }, ); + // onGenerateRoute: (settings) { + // if (settings.name?.contains("/watch?") == true) { + // return MaterialPageRoute(builder: (context) { + // return VideoDetailsScreen( + // vm: VideoDetailsViewModel.from(settings.name!)); + // }); + // } else if (settings.name == "/") { + // return configuredHomeWidget( + // 'Home', "${server.domain}/apiv2/feeds/home", true); + // } else if (settings.name == "/trending") { + // return configuredHomeWidget('Trending Content', + // "${server.domain}/apiv2/feeds/trending", true); + // } else if (settings.name == "/new") { + // return configuredHomeWidget( + // 'New Content', "${server.domain}/apiv2/feeds/new", true); + // } else if (settings.name == "/firstUploads") { + // return configuredHomeWidget('First Uploads', + // "${server.domain}/apiv2/feeds/firstUploads", true); + // } else if (settings.name?.contains("/userChannel/") == true) { + // var last = settings.name?.split("/userChannel/").last ?? "threespeak"; + // return MaterialPageRoute(builder: (context) { + // return UserChannelScreen(owner: last); + // }); + // } else if (settings.name?.contains('/community/') == true) { + // var last = settings.name?.split("/community/").last ?? + // "hive-167922?name=LeoFinance"; + // var comps = last.split("?name="); + // return MaterialPageRoute(builder: (context) { + // return CommunityDetailScreen(name: comps[0], title: comps[1]); + // }); + // } else if (settings.name == "/leaderboard") { + // return MaterialPageRoute(builder: (context) { + // return const LeaderboardScreen(); + // }); + // } else if (settings.name == "/communities") { + // return MaterialPageRoute(builder: (context) { + // return const CommunitiesScreen(); + // }); + // } + // assert(false, 'Need to implement ${settings.name}'); + // return null; + // }, + // ); } } diff --git a/lib/src/screens/communities_screen/communities_screen.dart b/lib/src/screens/communities_screen/communities_screen.dart index b41db8b4..d4b19235 100644 --- a/lib/src/screens/communities_screen/communities_screen.dart +++ b/lib/src/screens/communities_screen/communities_screen.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/communities_models/request/communities_request_model.dart'; import 'package:acela/src/models/communities_models/response/communities_response_models.dart'; +import 'package:acela/src/screens/communities_screen/community_details/community_details_screen.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/retry.dart'; @@ -40,8 +41,9 @@ class _CommunitiesScreenState extends State { title: Text(item.title), subtitle: Text(item.about), onTap: () { - Navigator.of(context) - .pushNamed('/community/${item.name}?name=${item.title}'); + var screen = CommunityDetailScreen(name: item.name, title: item.title); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); }, ); } diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index 14a6e0e8..695d92a7 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -2,7 +2,9 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/communities_models/request/community_details_request.dart'; import 'package:acela/src/models/communities_models/response/community_details_response_models.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; @@ -77,12 +79,15 @@ class _CommunityDetailScreenState extends State } void onTap(HomeFeedItem item) { - Navigator.of(context) - .pushNamed(VideoDetailsScreen.routeName(item.author, item.permlink)); + var viewModel = + VideoDetailsViewModel(author: item.author, permlink: item.permlink); + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => VideoDetailsScreen(vm: viewModel))); } void onUserTap(HomeFeedItem item) { - Navigator.of(context).pushNamed("/userChannel/${item.author}"); + Navigator.of(context).push(MaterialPageRoute( + builder: (c) => UserChannelScreen(owner: item.author))); } Widget _tileTitle(HomeFeedItem item, BuildContext context, diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index ad4d2afc..8763f16b 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -1,12 +1,10 @@ +import 'package:acela/src/screens/communities_screen/communities_screen.dart'; +import 'package:acela/src/screens/home_screen/home_screen.dart'; +import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; import 'package:flutter/material.dart'; class DrawerScreen extends StatelessWidget { - const DrawerScreen( - {Key? key, required this.isDarkMode, required this.switchDarkMode}) - : super(key: key); - - final bool isDarkMode; - final Function switchDarkMode; + const DrawerScreen({Key? key}) : super(key: key); Widget _homeMenu(BuildContext context) { return ListTile( @@ -14,7 +12,8 @@ class DrawerScreen extends StatelessWidget { title: const Text("Home"), onTap: () { Navigator.pop(context); - Navigator.of(context).pushReplacementNamed("/"); + var route = MaterialPageRoute(builder: (context) => HomeScreen.home()); + Navigator.of(context).pushReplacement(route); }, ); } @@ -25,7 +24,9 @@ class DrawerScreen extends StatelessWidget { title: const Text("First Uploads"), onTap: () { Navigator.pop(context); - Navigator.of(context).pushReplacementNamed("/firstUploads"); + var route = + MaterialPageRoute(builder: (context) => HomeScreen.firstUploads()); + Navigator.of(context).pushReplacement(route); }, ); } @@ -36,7 +37,9 @@ class DrawerScreen extends StatelessWidget { title: const Text("Trending Content"), onTap: () { Navigator.pop(context); - Navigator.of(context).pushReplacementNamed("/trending"); + var route = + MaterialPageRoute(builder: (context) => HomeScreen.trending()); + Navigator.of(context).pushReplacement(route); }, ); } @@ -47,7 +50,9 @@ class DrawerScreen extends StatelessWidget { title: const Text("New Content"), onTap: () { Navigator.pop(context); - Navigator.of(context).pushReplacementNamed("/new"); + var route = + MaterialPageRoute(builder: (context) => HomeScreen.newContent()); + Navigator.of(context).pushReplacement(route); }, ); } @@ -58,7 +63,8 @@ class DrawerScreen extends StatelessWidget { title: const Text("Communities"), onTap: () { Navigator.pop(context); - Navigator.of(context).pushNamed("/communities"); + Navigator.of(context) + .push(MaterialPageRoute(builder: (c) => const CommunitiesScreen())); }, ); } @@ -69,22 +75,23 @@ class DrawerScreen extends StatelessWidget { title: const Text("Leaderboard"), onTap: () { Navigator.pop(context); - Navigator.of(context).pushNamed("/leaderboard"); + Navigator.of(context) + .push(MaterialPageRoute(builder: (c) => const LeaderboardScreen())); }, ); } - Widget _changeTheme() { - return ListTile( - leading: isDarkMode - ? const Icon(Icons.wb_sunny) - : const Icon(Icons.mode_night), - title: const Text("Change Theme"), - onTap: () { - switchDarkMode(); - }, - ); - } + // Widget _changeTheme() { + // return ListTile( + // leading: !isDarkMode + // ? const Icon(Icons.wb_sunny) + // : const Icon(Icons.mode_night), + // title: const Text("Change Theme"), + // onTap: () { + // switchDarkMode(); + // }, + // ); + // } Widget _drawerHeader(BuildContext context) { return DrawerHeader( @@ -133,8 +140,8 @@ class DrawerScreen extends StatelessWidget { _divider(), _leaderBoard(context), _divider(), - _changeTheme(), - _divider(), + // _changeTheme(), + // _divider(), ], ); } diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 9776147f..5fa10cec 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -1,24 +1,56 @@ +import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/widgets/retry.dart'; import 'package:flutter/material.dart'; import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; class HomeScreen extends StatefulWidget { - const HomeScreen({Key? key, - required this.path, - required this.showDrawer, - required this.title, - required this.isDarkMode, - required this.switchDarkMode}) + const HomeScreen( + {Key? key, + required this.path, + required this.showDrawer, + required this.title}) : super(key: key); final String path; final bool showDrawer; final String title; - final bool isDarkMode; - final Function switchDarkMode; + + factory HomeScreen.trending() { + return HomeScreen( + title: 'Trending Content', + showDrawer: true, + path: "${server.domain}/apiv2/feeds/trending", + ); + } + + factory HomeScreen.home() { + return HomeScreen( + title: 'Home', + showDrawer: true, + path: "${server.domain}/apiv2/feeds/Home", + ); + } + + factory HomeScreen.newContent() { + return HomeScreen( + title: 'Home', + showDrawer: true, + path: "${server.domain}/apiv2/feeds/new", + ); + } + + factory HomeScreen.firstUploads() { + return HomeScreen( + title: 'Home', + showDrawer: true, + path: "${server.domain}/apiv2/feeds/firstUploads", + ); + } @override _HomeScreenState createState() => _HomeScreenState(); @@ -37,13 +69,16 @@ class _HomeScreenState extends State { } void onTap(HomeFeedItem item) { - Navigator.of(context) - .pushNamed(VideoDetailsScreen.routeName(item.author, item.permlink)); + var viewModel = + VideoDetailsViewModel(author: item.author, permlink: item.permlink); + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => VideoDetailsScreen(vm: viewModel))); } void onUserTap(HomeFeedItem item) { if (!widget.path.contains(item.author)) { - Navigator.of(context).pushNamed("/userChannel/${item.author}"); + Navigator.of(context).push( + MaterialPageRoute(builder: (c) => UserChannelScreen(owner: item.author))); } } @@ -70,9 +105,8 @@ class _HomeScreenState extends State { height: 40, width: 40, child: CircleAvatar( - backgroundImage: Image - .asset("assets/branding/three_speak_icon.png") - .image, + backgroundImage: + Image.asset("assets/branding/three_speak_icon.png").image, backgroundColor: Colors.transparent, radius: 100, ), @@ -80,28 +114,21 @@ class _HomeScreenState extends State { } Widget _header() { - return Row( - children: [ - _threeSpeakIcon(), - const SizedBox(width: 10), - Text(widget.title), - ] - ); + return Row(children: [ + _threeSpeakIcon(), + const SizedBox(width: 10), + Text(widget.title), + ]); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(widget.title), //_header(), + title: Text(widget.title), ), body: _screen(), - drawer: widget.showDrawer - ? DrawerScreen( - isDarkMode: widget.isDarkMode, - switchDarkMode: widget.switchDarkMode, - ) - : null, + drawer: widget.showDrawer ? const DrawerScreen() : null, ); } } diff --git a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart index 66796aab..629e3cdc 100644 --- a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart +++ b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart @@ -2,6 +2,7 @@ import 'dart:developer'; import 'dart:core'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/leaderboard_models/leaderboard_model.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/retry.dart'; @@ -41,7 +42,8 @@ class _LeaderboardScreenState extends State { } void onUserTap(String author) { - Navigator.of(context).pushNamed("/userChannel/$author"); + Navigator.of(context).push( + MaterialPageRoute(builder: (c) => UserChannelScreen(owner: author))); } Widget _medalTile(LeaderboardResponseItem item, String medal) { diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart index 55e75bb6..7fea97ce 100644 --- a/lib/src/screens/user_channel_screen/user_channel_videos.dart +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:acela/src/widgets/loading_screen.dart'; @@ -74,9 +75,10 @@ class _UserChannelVideosState extends State return ListView.separated( itemBuilder: (context, index) { return _listTile(data[index], context, (item) { - log("tapped on item ${item.permlink}"); - Navigator.of(context).pushNamed( - VideoDetailsScreen.routeName(item.author, item.permlink)); + var viewModel = + VideoDetailsViewModel(author: item.author, permlink: item.permlink); + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => VideoDetailsScreen(vm: viewModel))); }, (owner) { log("tapped on user ${owner.author}"); }); diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 3056a57c..2e47153d 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -1,8 +1,8 @@ -import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; import 'package:acela/src/screens/video_details_screen/video_details_info.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; @@ -20,10 +20,6 @@ class VideoDetailsScreen extends StatefulWidget { const VideoDetailsScreen({Key? key, required this.vm}) : super(key: key); final VideoDetailsViewModel vm; - static String routeName(String owner, String permLink) { - return '/watch?owner=$owner&permlink=$permLink'; - } - @override _VideoDetailsScreenState createState() => _VideoDetailsScreenState(); } @@ -46,7 +42,8 @@ class _VideoDetailsScreenState extends State { } void onUserTap() { - Navigator.of(context).pushNamed("/userChannel/${widget.vm.author}"); + Navigator.of(context).push(MaterialPageRoute( + builder: (c) => UserChannelScreen(owner: widget.vm.author))); } // used when there is an error state in loading video info @@ -279,7 +276,8 @@ class _VideoDetailsScreenState extends State { title: item.title, subtitle: "👤 ${item.owner}", onUserTap: () { - Navigator.of(context).pushNamed("/userChannel/${item.owner}"); + Navigator.of(context).push(MaterialPageRoute( + builder: (c) => UserChannelScreen(owner: item.owner))); }, ); } diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index 4c412273..a16840bb 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -7,46 +7,11 @@ import 'package:http/http.dart' show get; import 'package:http/http.dart' as http; class VideoDetailsViewModel { - // view - String path; String author; String permlink; VideoDetailsViewModel( - {required this.path, required this.author, required this.permlink}); - - factory VideoDetailsViewModel.from(String path) { - if (!path.contains("owner=") || !path.contains("permlink=")) { - path = "/watch?owner=sagarkothari88&permlink=gqbffyah"; - } - var comps = path - .replaceAll("?", "&") - .split("&") - .where((element) => - element.contains('owner=') || element.contains('permlink=')) - .toList(); - if (comps.length < 2) { - comps = "/watch?owner=sagarkothari88&permlink=gqbffyah" - .replaceAll("?", "&") - .split("&") - .where((element) => - element.contains('owner=') || element.contains('permlink=')) - .toList(); - } - comps.sort(); - var firstComp = comps[0].split("="); - if (firstComp.length < 2) { - firstComp[1] = "sagarkothari88"; - } - var secondComp = comps[1].split("="); - if (secondComp.length < 2) { - secondComp[1] = "gqbffyah"; - } - var author = firstComp[1]; - var permlink = secondComp[1]; - return VideoDetailsViewModel( - path: path, author: author, permlink: permlink); - } + {required this.author, required this.permlink}); Future getVideoDetails() async { final endPoint = From 466e068ec31b941f3215110c3b69cb14c3f510ec Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sat, 12 Mar 2022 07:12:26 +0530 Subject: [PATCH 047/466] New bottom navigation integrated. All screen widgets are refactored. Video thumbnail size issue fixed. --- .flutter-plugins-dependencies | 2 +- .packages | 2 +- ios/Podfile.lock | 4 +- lib/main.dart | 97 ++++++++++--------- .../communities_screen.dart | 7 +- .../community_details_screen.dart | 2 + lib/src/screens/home_screen/home_screen.dart | 29 +----- .../home_screen/home_screen_widgets.dart | 12 ++- .../user_channel_profile.dart | 1 + .../user_channel_videos.dart | 2 + .../video_details_screen.dart | 2 + lib/src/widgets/list_tile_video.dart | 74 ++++---------- 12 files changed, 92 insertions(+), 142 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index d41f6bc1..8ff14204 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-11 18:30:56.262624","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-12 07:06:39.878216","version":"2.10.3"} \ No newline at end of file diff --git a/.packages b/.packages index 50855a8e..ba2e0d80 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-03-10 09:39:27.123034. +# Generated by pub on 2022-03-12 07:06:39.618102. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3a0cbbf2..ad3c0417 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,7 +1,7 @@ PODS: - Firebase/CoreOnly (8.11.0): - FirebaseCore (= 8.11.0) - - firebase_core (1.12.0): + - firebase_core (1.13.1): - Firebase/CoreOnly (= 8.11.0) - Flutter - FirebaseCore (8.11.0): @@ -71,7 +71,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Firebase: 44dd9724c84df18b486639e874f31436eaa9a20c - firebase_core: 443bccfd6aa6b42f07be365b500773dc69db2d87 + firebase_core: 08f6a85f62060111de5e98d6a214810d11365de9 FirebaseCore: 2f4f85b453cc8fea4bb2b37e370007d2bcafe3f0 FirebaseCoreDiagnostics: 64d9709d804a6c25bd77841371c1fcfd909d5601 Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a diff --git a/lib/main.dart b/lib/main.dart index 562dd7d1..2d3ffdb6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; +import 'package:acela/src/screens/communities_screen/communities_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; @@ -20,6 +22,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { final Future _fbApp = Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + var _index = 0; Widget futureBuilder(Widget withWidget) { return FutureBuilder( @@ -41,51 +44,57 @@ class _MyAppState extends State { Widget build(BuildContext context) { return MaterialApp( title: 'Acela - 3Speak App', - home: HomeScreen.home(), + home: SafeArea( + child: Scaffold( + body: IndexedStack( + children: [ + HomeScreen.home(), + HomeScreen.trending(), + HomeScreen.newContent(), + HomeScreen.firstUploads(), + const CommunitiesScreen(), + ], + index: _index, + ), + bottomNavigationBar: BottomNavigationBar( + onTap: (index) { + log("User tapped on index $index"); + setState(() { + _index = index; + }); + }, + currentIndex: _index, + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + label: 'Home', + backgroundColor: Colors.black87, + ), + BottomNavigationBarItem( + icon: Icon(Icons.local_fire_department), + label: 'Trending', + // backgroundColor: Theme.of(context).primaryColor, + ), + BottomNavigationBarItem( + icon: Icon(Icons.play_arrow), + label: 'New', + // backgroundColor: Theme.of(context).primaryColor, + ), + BottomNavigationBarItem( + icon: Icon(Icons.emoji_emotions_outlined), + label: 'First Uploads', + // backgroundColor: Theme.of(context).primaryColor, + ), + BottomNavigationBarItem( + icon: Icon(Icons.people_sharp), + label: 'Communities', + // backgroundColor: Theme.of(context).primaryColor, + ), + ], + ), + ), + ), debugShowCheckedModeBanner: false, ); - // onGenerateRoute: (settings) { - // if (settings.name?.contains("/watch?") == true) { - // return MaterialPageRoute(builder: (context) { - // return VideoDetailsScreen( - // vm: VideoDetailsViewModel.from(settings.name!)); - // }); - // } else if (settings.name == "/") { - // return configuredHomeWidget( - // 'Home', "${server.domain}/apiv2/feeds/home", true); - // } else if (settings.name == "/trending") { - // return configuredHomeWidget('Trending Content', - // "${server.domain}/apiv2/feeds/trending", true); - // } else if (settings.name == "/new") { - // return configuredHomeWidget( - // 'New Content', "${server.domain}/apiv2/feeds/new", true); - // } else if (settings.name == "/firstUploads") { - // return configuredHomeWidget('First Uploads', - // "${server.domain}/apiv2/feeds/firstUploads", true); - // } else if (settings.name?.contains("/userChannel/") == true) { - // var last = settings.name?.split("/userChannel/").last ?? "threespeak"; - // return MaterialPageRoute(builder: (context) { - // return UserChannelScreen(owner: last); - // }); - // } else if (settings.name?.contains('/community/') == true) { - // var last = settings.name?.split("/community/").last ?? - // "hive-167922?name=LeoFinance"; - // var comps = last.split("?name="); - // return MaterialPageRoute(builder: (context) { - // return CommunityDetailScreen(name: comps[0], title: comps[1]); - // }); - // } else if (settings.name == "/leaderboard") { - // return MaterialPageRoute(builder: (context) { - // return const LeaderboardScreen(); - // }); - // } else if (settings.name == "/communities") { - // return MaterialPageRoute(builder: (context) { - // return const CommunitiesScreen(); - // }); - // } - // assert(false, 'Need to implement ${settings.name}'); - // return null; - // }, - // ); } } diff --git a/lib/src/screens/communities_screen/communities_screen.dart b/lib/src/screens/communities_screen/communities_screen.dart index d4b19235..b0347570 100644 --- a/lib/src/screens/communities_screen/communities_screen.dart +++ b/lib/src/screens/communities_screen/communities_screen.dart @@ -86,11 +86,6 @@ class _CommunitiesScreenState extends State { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text("Communities"), - ), - body: _body(), - ); + return _body(); } } diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index 695d92a7..7e31079d 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -112,6 +112,8 @@ class _CommunityDetailScreenState extends State Widget _listTile(HomeFeedItem item, BuildContext context, Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { return ListTile( + contentPadding: EdgeInsets.zero, + minVerticalPadding: 0, title: _tileTitle(item, context, onUserTap), onTap: () { onTap(item); diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 5fa10cec..7630a313 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -100,35 +100,8 @@ class _HomeScreenState extends State { ); } - Widget _threeSpeakIcon() { - return SizedBox( - height: 40, - width: 40, - child: CircleAvatar( - backgroundImage: - Image.asset("assets/branding/three_speak_icon.png").image, - backgroundColor: Colors.transparent, - radius: 100, - ), - ); - } - - Widget _header() { - return Row(children: [ - _threeSpeakIcon(), - const SizedBox(width: 10), - Text(widget.title), - ]); - } - @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: _screen(), - drawer: widget.showDrawer ? const DrawerScreen() : null, - ); + return _screen(); } } diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index 1cc0fd24..0a0933e1 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -33,6 +33,8 @@ class HomeScreenWidgets { Widget _listTile(HomeFeedItem item, BuildContext context, Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { return ListTile( + contentPadding: EdgeInsets.zero, + minVerticalPadding: 0, title: _tileTitle(item, context, onUserTap), onTap: () { onTap(item); @@ -44,15 +46,15 @@ class HomeScreenWidgets { Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { return RefreshIndicator( onRefresh: onRefresh, - child:ListView.separated( - physics: const AlwaysScrollableScrollPhysics(), + child: ListView.separated( + padding: EdgeInsets.zero, itemBuilder: (context, index) { return _listTile(list[index], context, onTap, onUserTap); }, - separatorBuilder: (context, index) => const Divider( - thickness: 0, height: 1, color: Colors.transparent), + separatorBuilder: (context, index) => + const Divider(thickness: 0, height: 15, color: Colors.transparent), itemCount: list.length, - ) + ), ); } } diff --git a/lib/src/screens/user_channel_screen/user_channel_profile.dart b/lib/src/screens/user_channel_screen/user_channel_profile.dart index 791f576b..ec5c8e16 100644 --- a/lib/src/screens/user_channel_screen/user_channel_profile.dart +++ b/lib/src/screens/user_channel_screen/user_channel_profile.dart @@ -49,6 +49,7 @@ class _UserChannelProfileWidgetState extends State Widget _descriptionMarkDown(String markDown) { return Markdown( + padding: const EdgeInsets.all(3), data: Utilities.removeAllHtmlTags(markDown), onTapLink: (text, url, title) { launch(url!); diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart index 7fea97ce..7ef859ab 100644 --- a/lib/src/screens/user_channel_screen/user_channel_videos.dart +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -57,6 +57,8 @@ class _UserChannelVideosState extends State Widget _listTile(HomeFeedItem item, BuildContext context, Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { return ListTile( + contentPadding: EdgeInsets.zero, + minVerticalPadding: 0, title: _tileTitle(item, context, onUserTap), onTap: () { onTap(item); diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 2e47153d..898993be 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -257,6 +257,8 @@ class _VideoDetailsScreenState extends State { ); } else { return ListTile( + contentPadding: EdgeInsets.zero, + minVerticalPadding: 0, title: videoRecommendationListItem(recommendations[index - 3]), ); } diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index f8ab0fa6..35dbff42 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -22,63 +22,32 @@ class ListTileVideo extends StatelessWidget { final String subtitle; final Function onUserTap; - Widget _commonContainer(BuildContext context, Widget child) { - return Container( - child: child, - ); - } - - Widget _listType(BuildContext context) { - double deviceWidth = MediaQuery.of(context).size.width; - double width = deviceWidth - 60 - 340; - return Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Image.network( - url, - width: deviceWidth - width - 60, - ), - Container(width: 10), - SizedBox( - width: width, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: Theme.of(context).textTheme.headline5, - ), - Container(height: 10), - Text(subtitle, style: Theme.of(context).textTheme.headline6), - ], - ), - ) - ], - ); - } - Widget _thumbnailType(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - FadeInImage.assetNetwork( - placeholder: placeholder, - image: server.resizedImage(url), - fit: BoxFit.cover, - placeholderErrorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { - return Image.asset(placeholder); - }, - imageErrorBuilder: (BuildContext context, Object error, StackTrace? stackTrace){ - return Image.asset(placeholder); - }, + SizedBox( + height: 220, + width: MediaQuery.of(context).size.width, + child: FadeInImage.assetNetwork( + placeholder: placeholder, + image: server.resizedImage(url), + fit: BoxFit.fitWidth, + placeholderErrorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { + return Image.asset(placeholder); + }, + imageErrorBuilder: (BuildContext context, Object error, StackTrace? stackTrace){ + return Image.asset(placeholder); + }, + ), ), Container( - padding: const EdgeInsets.all(10), + padding: const EdgeInsets.all(3), child: Row( children: [ GestureDetector( child: CustomCircleAvatar( - height: 40, width: 40, url: userThumbUrl), + height: 45, width: 45, url: userThumbUrl), onTap: () { onUserTap(); }, @@ -88,10 +57,9 @@ class ListTileVideo extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title, style: Theme.of(context).textTheme.bodyText2), - Container(height: 5), + Text(title, style: Theme.of(context).textTheme.bodyText1), Text(subtitle, - style: Theme.of(context).textTheme.bodyText1), + style: Theme.of(context).textTheme.bodyText2), ], ), ) @@ -104,10 +72,6 @@ class ListTileVideo extends StatelessWidget { @override Widget build(BuildContext context) { - ScreenType type = FormFactor.getFormFactor(context); - Widget widget = type == ScreenType.desktop || type == ScreenType.tablet - ? _listType(context) - : _thumbnailType(context); - return _commonContainer(context, widget); + return _thumbnailType(context); } } From 0e3d7bc52788d6ac8454a40d87f11069146b2bf4 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 14 Mar 2022 07:44:01 +0530 Subject: [PATCH 048/466] bringing back the drawer & theme switching. --- .flutter-plugins-dependencies | 2 +- .packages | 2 +- lib/main.dart | 72 +++++-------------- lib/src/bloc/server.dart | 10 +++ .../communities_screen.dart | 7 +- .../screens/drawer_screen/drawer_screen.dart | 29 ++++---- lib/src/screens/home_screen/home_screen.dart | 12 +++- pubspec.yaml | 2 +- 8 files changed, 63 insertions(+), 73 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 8ff14204..f09a0cbb 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-12 07:06:39.878216","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-14 07:42:46.741153","version":"2.10.3"} \ No newline at end of file diff --git a/.packages b/.packages index ba2e0d80..b48ae442 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-03-12 07:06:39.618102. +# Generated by pub on 2022-03-14 07:23:32.186622. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ diff --git a/lib/main.dart b/lib/main.dart index 2d3ffdb6..83922cdc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,10 @@ -import 'dart:developer'; -import 'package:acela/src/screens/communities_screen/communities_screen.dart'; +import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'firebase_options.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:provider/provider.dart'; Future main() async { await dotenv.load(fileName: ".env"); @@ -22,7 +22,6 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { final Future _fbApp = Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); - var _index = 0; Widget futureBuilder(Widget withWidget) { return FutureBuilder( @@ -42,59 +41,26 @@ class _MyAppState extends State { // This widget is the root of your application. @override Widget build(BuildContext context) { + return StreamProvider.value( + value: server.theme, + initialData: true, + child: const AcelaApp(), + ); + } +} + +class AcelaApp extends StatelessWidget { + const AcelaApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + var isDarkMode = Provider.of(context); return MaterialApp( title: 'Acela - 3Speak App', - home: SafeArea( - child: Scaffold( - body: IndexedStack( - children: [ - HomeScreen.home(), - HomeScreen.trending(), - HomeScreen.newContent(), - HomeScreen.firstUploads(), - const CommunitiesScreen(), - ], - index: _index, - ), - bottomNavigationBar: BottomNavigationBar( - onTap: (index) { - log("User tapped on index $index"); - setState(() { - _index = index; - }); - }, - currentIndex: _index, - items: const [ - BottomNavigationBarItem( - icon: Icon(Icons.home), - label: 'Home', - backgroundColor: Colors.black87, - ), - BottomNavigationBarItem( - icon: Icon(Icons.local_fire_department), - label: 'Trending', - // backgroundColor: Theme.of(context).primaryColor, - ), - BottomNavigationBarItem( - icon: Icon(Icons.play_arrow), - label: 'New', - // backgroundColor: Theme.of(context).primaryColor, - ), - BottomNavigationBarItem( - icon: Icon(Icons.emoji_emotions_outlined), - label: 'First Uploads', - // backgroundColor: Theme.of(context).primaryColor, - ), - BottomNavigationBarItem( - icon: Icon(Icons.people_sharp), - label: 'Communities', - // backgroundColor: Theme.of(context).primaryColor, - ), - ], - ), - ), - ), + home: HomeScreen.home(), + theme: isDarkMode ? ThemeData.dark() : ThemeData.light(), debugShowCheckedModeBanner: false, ); } } + diff --git a/lib/src/bloc/server.dart b/lib/src/bloc/server.dart index 1caba343..22967f03 100644 --- a/lib/src/bloc/server.dart +++ b/lib/src/bloc/server.dart @@ -21,6 +21,16 @@ class Server { } final String hiveDomain = "https://api.hive.blog"; + + final _controller = StreamController(); + + Stream get theme { + return _controller.stream; + } + + void changeTheme(bool value) async { + _controller.sink.add(!value); + } } Server server = Server(); \ No newline at end of file diff --git a/lib/src/screens/communities_screen/communities_screen.dart b/lib/src/screens/communities_screen/communities_screen.dart index b0347570..d4b19235 100644 --- a/lib/src/screens/communities_screen/communities_screen.dart +++ b/lib/src/screens/communities_screen/communities_screen.dart @@ -86,6 +86,11 @@ class _CommunitiesScreenState extends State { @override Widget build(BuildContext context) { - return _body(); + return Scaffold( + appBar: AppBar( + title: const Text("Communities"), + ), + body: _body(), + ); } } diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 8763f16b..e9a6dc0d 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -1,7 +1,9 @@ +import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/screens/communities_screen/communities_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class DrawerScreen extends StatelessWidget { const DrawerScreen({Key? key}) : super(key: key); @@ -81,17 +83,18 @@ class DrawerScreen extends StatelessWidget { ); } - // Widget _changeTheme() { - // return ListTile( - // leading: !isDarkMode - // ? const Icon(Icons.wb_sunny) - // : const Icon(Icons.mode_night), - // title: const Text("Change Theme"), - // onTap: () { - // switchDarkMode(); - // }, - // ); - // } + Widget _changeTheme(BuildContext context) { + var isDarkMode = Provider.of(context); + return ListTile( + leading: !isDarkMode + ? const Icon(Icons.wb_sunny) + : const Icon(Icons.mode_night), + title: const Text("Change Theme"), + onTap: () async { + server.changeTheme(isDarkMode); + }, + ); + } Widget _drawerHeader(BuildContext context) { return DrawerHeader( @@ -140,8 +143,8 @@ class DrawerScreen extends StatelessWidget { _divider(), _leaderBoard(context), _divider(), - // _changeTheme(), - // _divider(), + _changeTheme(context), + _divider(), ], ); } diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 7630a313..0e0e3137 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -38,7 +38,7 @@ class HomeScreen extends StatefulWidget { factory HomeScreen.newContent() { return HomeScreen( - title: 'Home', + title: 'New Content', showDrawer: true, path: "${server.domain}/apiv2/feeds/new", ); @@ -46,7 +46,7 @@ class HomeScreen extends StatefulWidget { factory HomeScreen.firstUploads() { return HomeScreen( - title: 'Home', + title: 'First Uploads', showDrawer: true, path: "${server.domain}/apiv2/feeds/firstUploads", ); @@ -102,6 +102,12 @@ class _HomeScreenState extends State { @override Widget build(BuildContext context) { - return _screen(); + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: _screen(), + drawer: widget.showDrawer ? const DrawerScreen() : null, + ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 469410b1..bf4d236d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+2 +version: 1.0.0+5 environment: sdk: ">=2.15.1 <3.0.0" From a736e7764b658300ee546ec10368ffab3fa193e9 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 14 Mar 2022 13:09:56 +0530 Subject: [PATCH 049/466] New Developer menu added. --- .flutter-plugins-dependencies | 2 +- ios/Runner.xcodeproj/project.pbxproj | 12 ++++++------ lib/src/screens/drawer_screen/drawer_screen.dart | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index f09a0cbb..3d0ec5d5 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-14 07:42:46.741153","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-14 08:06:09.352737","version":"2.10.3"} \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index d5d51a33..4dbf7206 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -332,7 +332,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -360,7 +360,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -407,7 +407,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -464,7 +464,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -494,7 +494,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -518,7 +518,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index e9a6dc0d..08df58c4 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -2,6 +2,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/screens/communities_screen/communities_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -96,6 +97,17 @@ class DrawerScreen extends StatelessWidget { ); } + Widget _developer(BuildContext context) { + return ListTile( + leading: const Icon(Icons.code), + title: const Text("Developer"), + onTap: () { + var route = MaterialPageRoute(builder: (context) => const UserChannelScreen(owner: 'sagarkothari88')); + Navigator.of(context).push(route); + }, + ); + } + Widget _drawerHeader(BuildContext context) { return DrawerHeader( child: Column( @@ -145,6 +157,8 @@ class DrawerScreen extends StatelessWidget { _divider(), _changeTheme(context), _divider(), + _developer(context), + _divider(), ], ); } From f55ee025f33d3ce1039972c69f19c31d44992e10 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 14 Mar 2022 13:44:04 +0530 Subject: [PATCH 050/466] Added search bar. --- .../leaderboard_models/leaderboard_model.dart | 3 - .../models/search/search_response_models.dart | 115 ++++++++++++++++++ lib/src/screens/home_screen/home_screen.dart | 7 ++ lib/src/screens/search/search_screen.dart | 69 +++++++++++ .../user_channel_videos.dart | 3 +- .../video_details_screen.dart | 2 +- 6 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 lib/src/models/search/search_response_models.dart create mode 100644 lib/src/screens/search/search_screen.dart diff --git a/lib/src/models/leaderboard_models/leaderboard_model.dart b/lib/src/models/leaderboard_models/leaderboard_model.dart index 8c993c85..52b80b92 100644 --- a/lib/src/models/leaderboard_models/leaderboard_model.dart +++ b/lib/src/models/leaderboard_models/leaderboard_model.dart @@ -1,9 +1,6 @@ import 'dart:convert'; import 'package:acela/src/utils/safe_convert.dart'; -// final jsonList = json.decode(jsonStr) as List; -// final list = jsonList.map((e) => LeaderboardResponseItem.fromJson(e)).toList(); - List leaderboardResponseItemFromString(String string) { final jsonList = json.decode(string) as List; final list = diff --git a/lib/src/models/search/search_response_models.dart b/lib/src/models/search/search_response_models.dart new file mode 100644 index 00000000..65384e55 --- /dev/null +++ b/lib/src/models/search/search_response_models.dart @@ -0,0 +1,115 @@ +import 'dart:convert'; +import 'package:acela/src/utils/safe_convert.dart'; + +class SearchResponseModels { + final double took; + final int hits; + final List results; + + SearchResponseModels({ + this.took = 0.0, + this.hits = 0, + required this.results, + }); + + factory SearchResponseModels.fromJson(Map? json) => + SearchResponseModels( + took: asDouble(json, 'took'), + hits: asInt(json, 'hits'), + results: asList(json, 'results') + .map((e) => SearchResponseResultsItem.fromJson(e)) + .toList(), + ); + + factory SearchResponseModels.fromJsonString(String jsonString) => + SearchResponseModels.fromJson(json.decode(jsonString)); + + Map toJson() => { + 'took': took, + 'hits': hits, + 'results': results.map((e) => e.toJson()), + }; +} + +class SearchResponseResultsItem { + final int id; + final String author; + final String permlink; + final String category; + final int children; + final String authorRep; + final String title; + final String titleMarked; + final String body; + final String bodyMarked; + final String imgUrl; + final double payout; + final int totalVotes; + final int upVotes; + final String createdAt; + final List tags; + final String app; + final int depth; + + SearchResponseResultsItem( + {this.id = 0, + this.author = "", + this.permlink = "", + this.category = "", + this.children = 0, + this.authorRep = "", + this.title = "", + this.titleMarked = "", + this.body = "", + this.bodyMarked = "", + this.imgUrl = "", + this.payout = 0.0, + this.totalVotes = 0, + this.upVotes = 0, + this.createdAt = "", + required this.tags, + this.app = "", + this.depth = 0}); + + factory SearchResponseResultsItem.fromJson(Map? json) => + SearchResponseResultsItem( + id: asInt(json, 'id'), + author: asString(json, 'author'), + permlink: asString(json, 'permlink'), + category: asString(json, 'category'), + children: asInt(json, 'children'), + authorRep: asString(json, 'author_rep'), + title: asString(json, 'title'), + titleMarked: asString(json, 'title_marked'), + body: asString(json, 'body'), + bodyMarked: asString(json, 'body_marked'), + imgUrl: asString(json, 'img_url'), + payout: asDouble(json, 'payout'), + totalVotes: asInt(json, 'total_votes'), + upVotes: asInt(json, 'up_votes'), + createdAt: asString(json, 'created_at'), + tags: asList(json, 'tags').map((e) => e.toString()).toList(), + app: asString(json, 'app'), + depth: asInt(json, 'depth')); + + Map toJson() => { + 'id': id, + 'author': author, + 'permlink': permlink, + 'category': category, + 'children': children, + 'author_rep': authorRep, + 'title': title, + 'title_marked': titleMarked, + 'body': body, + 'body_marked': bodyMarked, + 'img_url': imgUrl, + 'payout': payout, + 'total_votes': totalVotes, + 'up_votes': upVotes, + 'created_at': createdAt, + 'tags': tags.map((e) => e), + 'app': app, + 'depth': depth + }; +} diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 0e0e3137..8b481ad0 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -2,6 +2,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; +import 'package:acela/src/screens/search/search_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; @@ -105,6 +106,12 @@ class _HomeScreenState extends State { return Scaffold( appBar: AppBar( title: Text(widget.title), + actions: [ + IconButton(onPressed: (){ + var route = MaterialPageRoute(builder: (context) => const SearchScreen()); + Navigator.of(context).push(route); + }, icon: const Icon(Icons.search)) + ], ), body: _screen(), drawer: widget.showDrawer ? const DrawerScreen() : null, diff --git a/lib/src/screens/search/search_screen.dart b/lib/src/screens/search/search_screen.dart new file mode 100644 index 00000000..8c0c2cf9 --- /dev/null +++ b/lib/src/screens/search/search_screen.dart @@ -0,0 +1,69 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; + +class SearchScreen extends StatefulWidget { + const SearchScreen({Key? key}) : super(key: key); + + @override + State createState() => _SearchScreenState(); +} + +class _SearchScreenState extends State { + var text = ''; + late TextEditingController _controller; + + Future search() async{ + var headers = { + 'Content-Type': 'application/json', + 'Authorization': dotenv.env['HIVE_SEARCHER_AUTH_KEY'] ?? '' + }; + var request = http.Request('POST', Uri.parse('https://api.hivesearcher.com/search')); + request.body = json.encode({ + "q": "sagarkothari88 Watch on 3speak type:post", + "sort": "newest" + }); + request.headers.addAll(headers); + + http.StreamedResponse response = await request.send(); + + if (response.statusCode == 200) { + log(await response.stream.bytesToString()); + } else { + log(response.reasonPhrase.toString()); + } + } + + @override + void initState() { + super.initState(); + _controller = TextEditingController(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: TextField( + controller: _controller, + onChanged: (value) { + log('Text changed to $value'); + }, + ), + ), + body: const Center( + child: Text('Text search'), + ), + ); + } +} diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart index 7ef859ab..ba0e95c6 100644 --- a/lib/src/screens/user_channel_screen/user_channel_videos.dart +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -85,8 +85,7 @@ class _UserChannelVideosState extends State log("tapped on user ${owner.author}"); }); }, - separatorBuilder: (context, index) => const Divider( - thickness: 0, height: 1, color: Colors.transparent), + separatorBuilder: (context, index) => const Divider(thickness: 0, height: 15, color: Colors.transparent), itemCount: data.length, ); } else { diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 898993be..ff8609b3 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -263,7 +263,7 @@ class _VideoDetailsScreenState extends State { ); } }, - separatorBuilder: (context, index) => Container(), + separatorBuilder: (context, index) => const Divider(thickness: 0, height: 15, color: Colors.transparent), itemCount: recommendations.length + 2, ), ); From 419127e6afcbd79b3c6225e497a06e751491ec6c Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 15 Mar 2022 10:11:34 +0530 Subject: [PATCH 051/466] integrated search. --- .flutter-plugins | 4 +- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 20 ++- .idea/libraries/Flutter_Plugins.xml | 4 +- .packages | 9 +- .../video_details_model/video_details.dart | 105 ++++++--------- lib/src/screens/about/about_home_screen.dart | 92 +++++++++++++ .../screens/drawer_screen/drawer_screen.dart | 57 ++++---- lib/src/screens/search/search_screen.dart | 124 ++++++++++++++---- .../video_details_view_model.dart | 2 +- pubspec.lock | 13 +- pubspec.yaml | 1 + 12 files changed, 293 insertions(+), 140 deletions(-) create mode 100644 lib/src/screens/about/about_home_screen.dart diff --git a/.flutter-plugins b/.flutter-plugins index 9d6ba3ff..7b3919be 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -12,8 +12,8 @@ url_launcher_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang. url_launcher_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/ url_launcher_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/ video_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.3.0/ -video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/ -video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/ +video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/ +video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/ video_player_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/ video_player_web_hls=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/ wakelock=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 3d0ec5d5..5fd18387 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-14 08:06:09.352737","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-15 07:27:05.023660","version":"2.10.3"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 1990b2ed..0909b507 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -68,7 +68,7 @@ - @@ -268,6 +268,13 @@ + + + + + + @@ -677,14 +684,14 @@ - - @@ -784,7 +791,7 @@ - + @@ -810,6 +817,7 @@ + @@ -867,8 +875,8 @@ - - + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 8f24dea2..70c6c533 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -6,13 +6,11 @@ - - @@ -21,6 +19,8 @@ + + diff --git a/.packages b/.packages index b48ae442..a3d9c482 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-03-14 07:23:32.186622. +# Generated by pub on 2022-03-15 07:26:47.345918. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ @@ -13,7 +13,7 @@ build:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/bu build_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_config-1.0.0/lib/ build_daemon:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_daemon-3.0.1/lib/ build_resolvers:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_resolvers-2.0.6/lib/ -build_runner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner-2.1.7/lib/ +build_runner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner-2.1.8/lib/ build_runner_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner_core-7.2.3/lib/ built_collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_collection-5.1.1/lib/ built_value:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_value-8.1.4/lib/ @@ -42,6 +42,7 @@ flutter_lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlan flutter_markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_markdown-0.6.9/lib/ flutter_test:file:///Applications/flutter/flutter/packages/flutter_test/lib/ flutter_web_plugins:file:///Applications/flutter/flutter/packages/flutter_web_plugins/lib/ +font_awesome_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/font_awesome_flutter-9.2.0/lib/ frontend_server_client:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/frontend_server_client-2.1.2/lib/ glob:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/glob-2.0.2/lib/ graphs:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/graphs-2.1.0/lib/ @@ -100,8 +101,8 @@ url_launcher_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub. vector_math:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.1/lib/ very_good_analysis:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/very_good_analysis-2.4.0/lib/ video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.3.0/lib/ -video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.0/lib/ -video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.0/lib/ +video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/lib/ +video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/lib/ video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.0/lib/ video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/lib/ video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/lib/ diff --git a/lib/src/models/video_details_model/video_details.dart b/lib/src/models/video_details_model/video_details.dart index 343355e2..af4c6336 100644 --- a/lib/src/models/video_details_model/video_details.dart +++ b/lib/src/models/video_details_model/video_details.dart @@ -1,56 +1,23 @@ import 'dart:convert'; import 'package:acela/src/utils/safe_convert.dart'; -VideoDetails videoDetailsFromJson(String str) => - VideoDetails.fromJson(json.decode(str)); - -String videoDetailsToJson(VideoDetails data) => json.encode(data.toJson()); - class VideoDetails { - // 2022-02-08T19:17:10.065Z final String created; - - // false final bool paid; - - // 5 final int views; final List tagsV2; - - // 6202bef63df91fd29d7cbd2d final String id; - - // iOS Development final String community; - - // gqbffyah final String permlink; - - // 203.333333 final double duration; - - // 98062751 final int size; - - // sagarkothari88 final String owner; - - // URL - https://acela-9c624.web.app/### What did I do?* Research & Experiments for * iOS App Deployment * Android App Deployment * Web-app Deployment* Deployed web-app on firebase hosting* Why App as an web-app? * With the features we've built - It's 99% same experience for web-app or app. * For now, we're deploying it as web-app so that we do not have to worry about Apple's approval process or Google's Play Store approval process.### What's next?* User's Channel Home page### Previous UpdatesIf you've not checked my previous videos, please check those.* Updates in 3 mins - 3Speak.tv app for iOS, Android & Web * https://3speak.tv/watch?v=sagarkothari88/nzvezwzc* Updates in 5 mins - 3Speak.tv App for iOS, Android & Web * https://3speak.tv/watch?v=sagarkothari88/hawmmhlq* How do I install 3Speak.tv app on my Android Device? * https://3speak.tv/watch?v=sagarkothari88/xtdlszgb* 3Speak App Update * https://3speak.tv/watch?v=sagarkothari88/mfmakjwp* 3Speak App Update * https://3speak.tv/watch?v=sagarkothari88/canucyoa* iOS App Update in 6 mins * https://3speak.tv/watch?v=sagarkothari88/bfvgzkkl* iOS App Update in 3 mins * https://3speak.tv/watch?v=sagarkothari88/xtlyduch* iOS App Update in 2 mins * https://3speak.tv/watch?v=sagarkothari88/iwdnghrnPlease please please up-vote my videos to keep me motivated. final String description; - - // ipfs://bafybeieh2ylatpwqaoah7ztbwwj43bm3v3v76ymb732tkzxyr4fq4ea3aq final String thumbnail; - - // How do I install app on my iPhone or on my Android? final String title; - - // https://images.hive.blog/p/99pyU5Ga1kwr5bsMXthzYLbcngN4W2P8NtU9TWTdHC3HaQbjuuRfKKVdjVfWMw2cQWSAejpKRAqR2gj56yBNVYN6UkvLX7djqZAu5a3HuWPbdhvhtLqLkUTqPszx6T1CMU?format=jpeg&mode=cover&width=340&height=191 final String thumbUrl; - - // https://ipfs-3speak.b-cdn.net/ipfs/bafybeieh2ylatpwqaoah7ztbwwj43bm3v3v76ymb732tkzxyr4fq4ea3aq/ final String baseThumbUrl; - // https://threespeakvideo.b-cdn.net/gqbffyah/default.m3u8 final String playUrl; VideoDetails({ @@ -72,41 +39,45 @@ class VideoDetails { this.playUrl = "", }); + factory VideoDetails.fromJsonString(String jsonString) => VideoDetails.fromJson(json.decode(jsonString)); + factory VideoDetails.fromJson(Map? json) => VideoDetails( - created: asString(json, 'created'), - paid: asBool(json, 'paid'), - views: asInt(json, 'views'), - tagsV2: asList(json, 'tags_v2').map((e) => e.toString()).toList(), - id: asString(json, '_id'), - community: asString(json, 'community'), - permlink: asString(json, 'permlink'), - duration: asDouble(json, 'duration'), - size: asInt(json, 'size'), - owner: asString(json, 'owner'), - description: asString(json, 'description'), - thumbnail: asString(json, 'thumbnail'), - title: asString(json, 'title'), - thumbUrl: asString(json, 'thumbUrl'), - baseThumbUrl: asString(json, 'baseThumbUrl'), - playUrl: asString(json, 'playUrl'), - ); + created: asString(json, 'created'), + paid: asBool(json, 'paid'), + views: asInt(json, 'views'), + tagsV2: asList(json, 'tags_v2').map((e) => e.toString()).toList(), + id: asString(json, '_id'), + community: asString(json, 'community'), + permlink: asString(json, 'permlink'), + duration: asDouble(json, 'duration'), + size: asInt(json, 'size'), + owner: asString(json, 'owner'), + description: asString(json, 'description'), + thumbnail: asString(json, 'thumbnail'), + title: asString(json, 'title'), + thumbUrl: asString(json, 'thumbUrl'), + baseThumbUrl: asString(json, 'baseThumbUrl'), + playUrl: asString(json, 'playUrl'), + ); + + String toJsonString() => json.encode(toJson()); Map toJson() => { - 'created': created, - 'paid': paid, - 'views': views, - 'tags_v2': tagsV2.map((e) => e), - '_id': id, - 'community': community, - 'permlink': permlink, - 'duration': duration, - 'size': size, - 'owner': owner, - 'description': description, - 'thumbnail': thumbnail, - 'title': title, - 'thumbUrl': thumbUrl, - 'baseThumbUrl': baseThumbUrl, - 'playUrl': playUrl, - }; + 'created': created, + 'paid': paid, + 'views': views, + 'tags_v2': tagsV2.map((e) => e), + '_id': id, + 'community': community, + 'permlink': permlink, + 'duration': duration, + 'size': size, + 'owner': owner, + 'description': description, + 'thumbnail': thumbnail, + 'title': title, + 'thumbUrl': thumbUrl, + 'baseThumbUrl': baseThumbUrl, + 'playUrl': playUrl, + }; } diff --git a/lib/src/screens/about/about_home_screen.dart b/lib/src/screens/about/about_home_screen.dart new file mode 100644 index 00000000..1aa27d21 --- /dev/null +++ b/lib/src/screens/about/about_home_screen.dart @@ -0,0 +1,92 @@ +import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +class AboutHomeScreen extends StatelessWidget { + const AboutHomeScreen({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('3Speak.tv'), + ), + body: ListView( + children: [ + ListTile( + leading: const Icon(Icons.info_outline), + title: const Text('About us'), + onTap: () { + + }, + ), + ListTile( + leading: const FaIcon(FontAwesomeIcons.question), + title: const Text('FAQ'), + onTap: () { + + }, + ), + ListTile( + leading: const FaIcon(FontAwesomeIcons.twitter), + title: const Text('Follow us on Twitter'), + onTap: () { + + }, + ), + ListTile( + leading: const FaIcon(FontAwesomeIcons.telegram), + title: const Text('Join us on Telegram'), + onTap: () { + + }, + ), + ListTile( + leading: const FaIcon(FontAwesomeIcons.discord), + title: const Text('Join us on Discord'), + onTap: () { + + }, + ), + ListTile( + leading: const FaIcon(FontAwesomeIcons.blog), + title: const Text('Visit blog - hive.blog/@threespeak'), + onTap: () { + + }, + ), + ListTile( + leading: const Icon(Icons.web), + title: const Text('Visit website - spk.network'), + onTap: () { + + }, + ), + ListTile( + leading: const Icon(Icons.web), + title: const Text('Visit website - 3speak.tv'), + onTap: () { + + }, + ), + ListTile( + leading: const Icon(Icons.picture_as_pdf), + title: const Text('Terms of service'), + onTap: () { + + }, + ), + ListTile( + leading: const Icon(Icons.developer_mode), + title: const Text('Who built this app?'), + onTap: () { + var screen = const UserChannelScreen(owner: 'sagarkothari88'); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + ), + ], + ), + ); + } +} diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 08df58c4..eea55789 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -1,4 +1,5 @@ import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/screens/about/about_home_screen.dart'; import 'package:acela/src/screens/communities_screen/communities_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; @@ -97,37 +98,33 @@ class DrawerScreen extends StatelessWidget { ); } - Widget _developer(BuildContext context) { - return ListTile( - leading: const Icon(Icons.code), - title: const Text("Developer"), - onTap: () { - var route = MaterialPageRoute(builder: (context) => const UserChannelScreen(owner: 'sagarkothari88')); - Navigator.of(context).push(route); - }, - ); - } - Widget _drawerHeader(BuildContext context) { return DrawerHeader( - child: Column( - children: [ - Image.asset( - "assets/branding/three_speak_icon.png", - width: 60, - height: 60, - ), - const SizedBox(height: 5), - Text( - "Acela", - style: Theme.of(context).textTheme.headline5, - ), - const SizedBox(height: 5), - Text( - "3Speak.tv", - style: Theme.of(context).textTheme.headline6, - ), - ], + child: InkWell( + child: Column( + children: [ + Image.asset( + "assets/branding/three_speak_icon.png", + width: 60, + height: 60, + ), + const SizedBox(height: 5), + Text( + "Acela", + style: Theme.of(context).textTheme.headline5, + ), + const SizedBox(height: 5), + Text( + "3Speak.tv", + style: Theme.of(context).textTheme.headline6, + ), + ], + ), + onTap: () { + // var screen = const AboutHomeScreen(); + // var route = MaterialPageRoute(builder: (_) => screen); + // Navigator.of(context).push(route); + }, ), ); } @@ -157,8 +154,6 @@ class DrawerScreen extends StatelessWidget { _divider(), _changeTheme(context), _divider(), - _developer(context), - _divider(), ], ); } diff --git a/lib/src/screens/search/search_screen.dart b/lib/src/screens/search/search_screen.dart index 8c0c2cf9..455e023d 100644 --- a/lib/src/screens/search/search_screen.dart +++ b/lib/src/screens/search/search_screen.dart @@ -1,10 +1,16 @@ +import 'dart:async'; import 'dart:developer'; - +import 'dart:convert'; +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/search/search_response_models.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; +import 'package:timeago/timeago.dart' as timeago; class SearchScreen extends StatefulWidget { const SearchScreen({Key? key}) : super(key: key); @@ -16,25 +22,38 @@ class SearchScreen extends StatefulWidget { class _SearchScreenState extends State { var text = ''; late TextEditingController _controller; + Timer? _timer; + List results = []; + var loading = false; - Future search() async{ + Future search(String term) async { var headers = { 'Content-Type': 'application/json', 'Authorization': dotenv.env['HIVE_SEARCHER_AUTH_KEY'] ?? '' }; - var request = http.Request('POST', Uri.parse('https://api.hivesearcher.com/search')); - request.body = json.encode({ - "q": "sagarkothari88 Watch on 3speak type:post", - "sort": "newest" - }); + var request = + http.Request('POST', Uri.parse('https://api.hivesearcher.com/search')); + request.body = + json.encode({"q": "$term Watch on 3speak type:post", "sort": "newest"}); request.headers.addAll(headers); - + setState(() { + loading = true; + }); http.StreamedResponse response = await request.send(); - + setState(() { + loading = false; + }); if (response.statusCode == 200) { - log(await response.stream.bytesToString()); + var result = SearchResponseModels.fromJsonString( + await response.stream.bytesToString()); + setState(() { + results = result.results; + }); } else { log(response.reasonPhrase.toString()); + setState(() { + results = []; + }); } } @@ -50,20 +69,79 @@ class _SearchScreenState extends State { super.dispose(); } - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: TextField( - controller: _controller, - onChanged: (value) { + PreferredSizeWidget _appBar() { + return AppBar( + title: TextField( + controller: _controller, + onChanged: (value) { + var timer = Timer(const Duration(seconds: 2), () { log('Text changed to $value'); - }, - ), + if (value.trim().length > 3) { + search(value.trim()); + } + }); + setState(() { + _timer?.cancel(); + _timer = timer; + }); + }, ), - body: const Center( - child: Text('Text search'), + ); + } + + Widget _searchResultListItem(SearchResponseResultsItem item) { + var created = DateTime.tryParse(item.createdAt); + String timeInString = + created != null ? "📆 ${timeago.format(created)}" : ""; + return ListTile( + contentPadding: EdgeInsets.zero, + minVerticalPadding: 0, + title: ListTileVideo( + placeholder: 'assets/branding/three_speak_logo.png', + url: item.imgUrl, + userThumbUrl: server.userOwnerThumb(item.author), + title: item.title, + subtitle: "👤 ${item.author} $timeInString ", + onUserTap: () { + var channel = UserChannelScreen(owner: item.author); + var route = MaterialPageRoute(builder: (_) => channel); + Navigator.of(context).push(route); + }, ), + onTap: () { + var vm = + VideoDetailsViewModel(author: item.author, permlink: item.permlink); + var details = VideoDetailsScreen(vm: vm); + var route = MaterialPageRoute(builder: (_) => details); + Navigator.of(context).push(route); + }, + ); + } + + Widget _searchResultListView() { + if (results.isEmpty && !loading) { + return const Center( + child: Text('No search result found'), + ); + } else if (loading) { + return const Center( + child: Text('Loading search results....'), + ); + } + return ListView.separated( + itemBuilder: (context, index) { + return _searchResultListItem(results[index]); + }, + separatorBuilder: (_, index) => + const Divider(thickness: 0, height: 15, color: Colors.transparent), + itemCount: results.length); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: _appBar(), + body: _searchResultListView(), ); } } diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index a16840bb..3b8691b6 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -18,7 +18,7 @@ class VideoDetailsViewModel { "${server.domain}/apiv2/@$author/$permlink"; var response = await get(Uri.parse(endPoint)); if (response.statusCode == 200) { - VideoDetails data = videoDetailsFromJson(response.body); + VideoDetails data = VideoDetails.fromJsonString(response.body); return data; } else { throw "Status code = ${response.statusCode}"; diff --git a/pubspec.lock b/pubspec.lock index 2a5636fe..9ac0597b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -70,7 +70,7 @@ packages: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.7" + version: "2.1.8" build_runner_core: dependency: transitive description: @@ -261,6 +261,13 @@ packages: description: flutter source: sdk version: "0.0.0" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "9.2.0" frontend_server_client: dependency: transitive description: @@ -671,14 +678,14 @@ packages: name: video_player_android url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.3.1" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.3.1" video_player_platform_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bf4d236d..1159ff74 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: sdk: flutter flutter_dotenv: ^5.0.2 flutter_markdown: ^0.6.9 + font_awesome_flutter: ^9.2.0 http: ^0.13.4 json_annotation: ^4.4.0 provider: ^6.0.2 From 5b54cac9f0a106bfafc873a5d41baf2c59c01af4 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 17 Mar 2022 15:46:53 +0530 Subject: [PATCH 052/466] Using same identifier as Android. --- .flutter-plugins | 2 +- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 12 ++++++------ .idea/libraries/Flutter_Plugins.xml | 2 +- .packages | 8 ++++---- ios/Runner.xcodeproj/project.pbxproj | 17 ++++++++++------- ios/Runner/GoogleService-Info.plist | 8 ++++---- ios/Runner/Info.plist | 2 +- lib/firebase_options.dart | 15 ++++----------- lib/src/screens/home_screen/home_screen.dart | 12 ++++++------ pubspec.lock | 6 +++--- pubspec.yaml | 2 +- 12 files changed, 42 insertions(+), 46 deletions(-) diff --git a/.flutter-plugins b/.flutter-plugins index 7b3919be..8d695806 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -2,7 +2,7 @@ firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/ firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/ share_plus=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/ -share_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/ +share_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/ share_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/ url_launcher=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.20/ url_launcher_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 5fd18387..54744ba6 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-15 07:27:05.023660","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-17 15:44:06.833149","version":"2.10.3"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 0909b507..9a021db9 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -117,7 +117,7 @@ - @@ -474,14 +474,14 @@ - - @@ -798,7 +798,7 @@ - + @@ -846,8 +846,8 @@ - - + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 70c6c533..cccf0420 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -12,7 +12,6 @@ - @@ -21,6 +20,7 @@ + diff --git a/.packages b/.packages index a3d9c482..2679c4fb 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-03-15 07:26:47.345918. +# Generated by pub on 2022-03-17 15:44:06.591326. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ @@ -20,7 +20,7 @@ built_value:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang. characters:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib/ charcode:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib/ checked_yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/checked_yaml-2.0.1/lib/ -chewie:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/chewie-1.3.0/lib/ +chewie:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/chewie-1.3.1/lib/ clock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib/ code_builder:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/code_builder-4.1.0/lib/ collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0/lib/ @@ -71,8 +71,8 @@ pub_semver:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.o pubspec_parse:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pubspec_parse-1.2.0/lib/ share_plus:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/lib/ share_plus_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-2.0.4/lib/ -share_plus_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.0.2/lib/ -share_plus_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_platform_interface-2.0.1/lib/ +share_plus_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/lib/ +share_plus_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_platform_interface-2.1.0/lib/ share_plus_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/lib/ share_plus_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-2.0.3/lib/ shelf:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.2.0/lib/ diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 4dbf7206..381a9816 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -8,7 +8,7 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 1B77A5C027A5C39000510271 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1B77A5BF27A5C39000510271 /* GoogleService-Info.plist */; }; + 1BBABA1B27E2F977000ABB58 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1BBABA1A27E2F977000ABB58 /* GoogleService-Info.plist */; }; 23F3017383FF2D45A9FFE1B2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 900CC1210BBABA2901A394FB /* Pods_Runner.framework */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; @@ -33,7 +33,7 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 1B77A5BF27A5C39000510271 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 1BBABA1A27E2F977000ABB58 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 3655DA9EF6F21F87FCBD0D8C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 571EA836831FEA283EA2C84D /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; @@ -122,7 +122,7 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - 1B77A5BF27A5C39000510271 /* GoogleService-Info.plist */, + 1BBABA1A27E2F977000ABB58 /* GoogleService-Info.plist */, ); path = Runner; sourceTree = ""; @@ -192,7 +192,7 @@ files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 1B77A5C027A5C39000510271 /* GoogleService-Info.plist in Resources */, + 1BBABA1B27E2F977000ABB58 /* GoogleService-Info.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -347,6 +347,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0.0; MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -369,7 +370,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = com.3speak.Acela; + PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -429,6 +430,7 @@ MARKETING_VERSION = 1.0.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -479,6 +481,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0.0; MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; @@ -503,7 +506,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = com.3speak.Acela; + PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -527,7 +530,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = com.3speak.Acela; + PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist index c0e7a352..c35d3307 100644 --- a/ios/Runner/GoogleService-Info.plist +++ b/ios/Runner/GoogleService-Info.plist @@ -3,9 +3,9 @@ CLIENT_ID - 252548198943-m20qel1pq01m3p8ivhfg9ac54600j8cg.apps.googleusercontent.com + 252548198943-ec3gnethnkvoudaat0lrobmq2t7mve8g.apps.googleusercontent.com REVERSED_CLIENT_ID - com.googleusercontent.apps.252548198943-m20qel1pq01m3p8ivhfg9ac54600j8cg + com.googleusercontent.apps.252548198943-ec3gnethnkvoudaat0lrobmq2t7mve8g API_KEY AIzaSyBhRRZgrQb8WfCKVMjOwC4jnK0XiMuK4YM GCM_SENDER_ID @@ -13,7 +13,7 @@ PLIST_VERSION 1 BUNDLE_ID - com.3speak.Acela + com.example.acela PROJECT_ID acela-9c624 STORAGE_BUCKET @@ -29,6 +29,6 @@ IS_SIGNIN_ENABLED GOOGLE_APP_ID - 1:252548198943:ios:de180e80d89dc46e355b2a + 1:252548198943:ios:2fcda030e33a7164355b2a \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 1ca996e7..6a4f1a40 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -13,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - acela + Acela 3Speak CFBundlePackageType APPL CFBundleShortVersionString diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart index 25f0b75e..4f166e28 100644 --- a/lib/firebase_options.dart +++ b/lib/firebase_options.dart @@ -17,7 +17,10 @@ import 'package:flutter/foundation.dart' class DefaultFirebaseOptions { static FirebaseOptions get currentPlatform { if (kIsWeb) { - return web; + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for web - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); } // ignore: missing_enum_constant_in_switch switch (defaultTargetPlatform) { @@ -34,16 +37,6 @@ class DefaultFirebaseOptions { ); } - static const FirebaseOptions web = FirebaseOptions( - apiKey: 'AIzaSyCBelYnHytHyCdgeuS__jPnDMspMwUEL6c', - appId: '1:252548198943:web:6d5db0a3012636d0355b2a', - messagingSenderId: '252548198943', - projectId: 'acela-9c624', - authDomain: 'acela-9c624.firebaseapp.com', - storageBucket: 'acela-9c624.appspot.com', - measurementId: 'G-L9X49S2EG1', - ); - static const FirebaseOptions android = FirebaseOptions( apiKey: 'AIzaSyDZlrKYsD3jlvFkfiXPg3bbVjizqMUqSnE', appId: '1:252548198943:android:ea163470c7c668c9355b2a', diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 8b481ad0..4c453220 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -106,12 +106,12 @@ class _HomeScreenState extends State { return Scaffold( appBar: AppBar( title: Text(widget.title), - actions: [ - IconButton(onPressed: (){ - var route = MaterialPageRoute(builder: (context) => const SearchScreen()); - Navigator.of(context).push(route); - }, icon: const Icon(Icons.search)) - ], + // actions: [ + // IconButton(onPressed: (){ + // var route = MaterialPageRoute(builder: (context) => const SearchScreen()); + // Navigator.of(context).push(route); + // }, icon: const Icon(Icons.search)) + // ], ), body: _screen(), drawer: widget.showDrawer ? const DrawerScreen() : null, diff --git a/pubspec.lock b/pubspec.lock index 9ac0597b..0f9bf792 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -119,7 +119,7 @@ packages: name: chewie url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" clock: dependency: transitive description: @@ -470,14 +470,14 @@ packages: name: share_plus_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.1.0" share_plus_web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1159ff74..ef65abd6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+5 +version: 1.0.0+6 environment: sdk: ">=2.15.1 <3.0.0" From 1ec30befcb218998bd27b464d3f33518c362a996 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 18 Mar 2022 06:35:28 +0530 Subject: [PATCH 053/466] Possible solution for loading payouts on each feed. --- .flutter-plugins-dependencies | 2 +- ios/Runner.xcodeproj/project.pbxproj | 12 +- .../hive_payout_response.dart | 49 ++++++ .../community_details_screen.dart | 2 + .../home_screen/home_screen_widgets.dart | 2 + lib/src/screens/search/search_screen.dart | 2 + .../user_channel_videos.dart | 2 + .../video_details_screen.dart | 2 + lib/src/widgets/list_tile_video.dart | 139 +++++++++++++++--- 9 files changed, 182 insertions(+), 30 deletions(-) create mode 100644 lib/src/models/home_screen_feed_models/hive_payout_response.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 54744ba6..a8925afa 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-17 15:44:06.833149","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-18 05:38:18.274851","version":"2.10.3"} \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 381a9816..2dcda7e1 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -332,7 +332,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -361,7 +361,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -408,7 +408,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -466,7 +466,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -497,7 +497,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -521,7 +521,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 6; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/lib/src/models/home_screen_feed_models/hive_payout_response.dart b/lib/src/models/home_screen_feed_models/hive_payout_response.dart new file mode 100644 index 00000000..cff10fba --- /dev/null +++ b/lib/src/models/home_screen_feed_models/hive_payout_response.dart @@ -0,0 +1,49 @@ +import 'dart:convert'; +import 'package:acela/src/utils/safe_convert.dart'; + +class HivePayoutResponse { + final String jsonrpc; + final HivePayoutResponseResult result; + + HivePayoutResponse({ + this.jsonrpc = "", + required this.result, + }); + + factory HivePayoutResponse.fromJson(Map? json) => HivePayoutResponse( + jsonrpc: asString(json, 'jsonrpc'), + result: HivePayoutResponseResult.fromJson(asMap(json, 'result')), + ); + + factory HivePayoutResponse.fromJsonString(String jsonString) => HivePayoutResponse.fromJson(json.decode(jsonString)); + + Map toJson() => { + 'jsonrpc': jsonrpc, + 'result': result.toJson(), + }; +} + +class HivePayoutResponseResult { + final String totalPayoutValue; + final String curatorPayoutValue; + final String pendingPayoutValue; + + HivePayoutResponseResult({ + this.totalPayoutValue = "", + this.curatorPayoutValue = "", + this.pendingPayoutValue = "", + }); + + factory HivePayoutResponseResult.fromJson(Map? json) => HivePayoutResponseResult( + totalPayoutValue: asString(json, 'total_payout_value'), + curatorPayoutValue: asString(json, 'curator_payout_value'), + pendingPayoutValue: asString(json, 'pending_payout_value'), + ); + + Map toJson() => { + 'total_payout_value': totalPayoutValue, + 'curator_payout_value': curatorPayoutValue, + 'pending_payout_value': pendingPayoutValue, + }; +} + diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index 7e31079d..3543349d 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -106,6 +106,8 @@ class _CommunityDetailScreenState extends State onUserTap: () { onUserTap(item); }, + user: item.author, + permlink: item.permlink, ); } diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index 0a0933e1..41f37a24 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -27,6 +27,8 @@ class HomeScreenWidgets { onUserTap: () { onUserTap(item); }, + user: item.author, + permlink: item.permlink, ); } diff --git a/lib/src/screens/search/search_screen.dart b/lib/src/screens/search/search_screen.dart index 455e023d..73131c91 100644 --- a/lib/src/screens/search/search_screen.dart +++ b/lib/src/screens/search/search_screen.dart @@ -107,6 +107,8 @@ class _SearchScreenState extends State { var route = MaterialPageRoute(builder: (_) => channel); Navigator.of(context).push(route); }, + user: item.author, + permlink: item.permlink, ), onTap: () { var vm = diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart index ba0e95c6..677f2190 100644 --- a/lib/src/screens/user_channel_screen/user_channel_videos.dart +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -51,6 +51,8 @@ class _UserChannelVideosState extends State onUserTap: () { onUserTap(item); }, + user: item.author, + permlink: item.permlink, ); } diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index ff8609b3..7db0345e 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -281,6 +281,8 @@ class _VideoDetailsScreenState extends State { Navigator.of(context).push(MaterialPageRoute( builder: (c) => UserChannelScreen(owner: item.owner))); }, + user: item.owner, + permlink: item.mediaid, ); } diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index 35dbff42..d8fdb8ce 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -1,19 +1,24 @@ import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/home_screen_feed_models/hive_payout_response.dart'; import 'package:acela/src/utils/form_factor.dart'; import 'package:flutter/material.dart'; import 'custom_circle_avatar.dart'; import '../utils/form_factor.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; class ListTileVideo extends StatelessWidget { - const ListTileVideo( - {Key? key, - required this.placeholder, - required this.url, - required this.userThumbUrl, - required this.title, - required this.subtitle, - required this.onUserTap}) - : super(key: key); + const ListTileVideo({ + Key? key, + required this.placeholder, + required this.url, + required this.userThumbUrl, + required this.title, + required this.subtitle, + required this.onUserTap, + required this.user, + required this.permlink, + }) : super(key: key); final String placeholder; final String url; @@ -21,25 +26,113 @@ class ListTileVideo extends StatelessWidget { final String title; final String subtitle; final Function onUserTap; + final String user; + final String permlink; + + Widget _errorIndicator() { + return Container( + height: 220, + decoration: BoxDecoration( + image: DecorationImage( + image: Image.asset(placeholder).image, + fit: BoxFit.fitWidth, + ), + ), + ); + } + + Widget _amount(double value) { + return SizedBox( + height: 220, + child: Row( + children: [ + const Spacer(), + Column( + children: [ + const Spacer(), + Container( + padding: const EdgeInsets.all(5), + decoration: const BoxDecoration( + borderRadius: BorderRadiusDirectional.all(Radius.circular(10)), + color: Colors.blueGrey + ), + child: Text('\$ $value'), + ), + const SizedBox(height: 5), + ], + ), + const Spacer(), + ], + ) + ); + } + + Future _futureHivePayout() async { + var request = http.Request('POST', Uri.parse('https://api.deathwing.me/')); + request.body = json.encode({ + "id": 0, + "jsonrpc": "2.0", + "method": "condenser_api.get_content", + "params": [user, permlink] + }); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + return HivePayoutResponse.fromJsonString(string); + } else { + throw response.reasonPhrase ?? 'Unknown Error'; + } + } + + Widget _hivePayoutLoader() { + return FutureBuilder( + builder: (context, snapshot) { + if (snapshot.hasData) { + var data = snapshot.data as HivePayoutResponse; + if (data.result.pendingPayoutValue == "0.000 HBD") { + var total = double + .parse(data.result.totalPayoutValue.replaceAll(' HBD', '')); + var curator = double + .parse(data.result.curatorPayoutValue.replaceAll(' HBD', '')); + return _amount(total + curator); + } else { + var value = double + .parse(data.result.pendingPayoutValue.replaceAll(' HBD', '')); + return _amount(value); + } + } else { + return Container(); + } + }, + future: _futureHivePayout(), + ); + } Widget _thumbnailType(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - SizedBox( - height: 220, - width: MediaQuery.of(context).size.width, - child: FadeInImage.assetNetwork( - placeholder: placeholder, - image: server.resizedImage(url), - fit: BoxFit.fitWidth, - placeholderErrorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { - return Image.asset(placeholder); - }, - imageErrorBuilder: (BuildContext context, Object error, StackTrace? stackTrace){ - return Image.asset(placeholder); - }, - ), + Stack( + children: [ + SizedBox( + height: 220, + width: MediaQuery.of(context).size.width, + child: FadeInImage.assetNetwork( + placeholder: placeholder, + image: server.resizedImage(url), + fit: BoxFit.fitWidth, + placeholderErrorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return _errorIndicator(); + }, + imageErrorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return _errorIndicator(); + }, + ), + ), + // _hivePayoutLoader(), + ], ), Container( padding: const EdgeInsets.all(3), From 498da55da9e634b176e30957f2340449c4e3a7cc Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 27 Mar 2022 18:54:23 +0530 Subject: [PATCH 054/466] Acela - 1.0.0 (9) release. --- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 8 ++++ .idea/libraries/Flutter_Plugins.xml | 2 +- .packages | 2 +- ios/Podfile.lock | 2 +- ios/Runner.xcodeproj/project.pbxproj | 12 ++--- lib/src/screens/home_screen/home_screen.dart | 21 ++++---- lib/src/widgets/list_tile_video.dart | 50 ++++++++++---------- pubspec.yaml | 2 +- 9 files changed, 56 insertions(+), 45 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index a8925afa..34543e9a 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-18 05:38:18.274851","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-27 12:59:20.712037","version":"2.10.3"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 9a021db9..bbf0ef04 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -9,6 +9,13 @@ + + + + + + @@ -893,6 +900,7 @@ + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index cccf0420..a5891bbf 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -19,8 +19,8 @@ - + diff --git a/.packages b/.packages index 2679c4fb..c70d7150 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-03-17 15:44:06.591326. +# Generated by pub on 2022-03-27 12:49:44.177171. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ad3c0417..3fce3e6f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -86,4 +86,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 56099e53bf102df458f588dbe78632cd13d5357b -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 2dcda7e1..b1425740 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -332,7 +332,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 9; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -361,7 +361,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -408,7 +408,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 9; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -466,7 +466,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 9; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -497,7 +497,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -521,7 +521,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 9; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 4c453220..9c39c690 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -2,13 +2,13 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; +import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; import 'package:acela/src/screens/search/search_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/widgets/retry.dart'; import 'package:flutter/material.dart'; -import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; class HomeScreen extends StatefulWidget { const HomeScreen( @@ -78,8 +78,8 @@ class _HomeScreenState extends State { void onUserTap(HomeFeedItem item) { if (!widget.path.contains(item.author)) { - Navigator.of(context).push( - MaterialPageRoute(builder: (c) => UserChannelScreen(owner: item.author))); + Navigator.of(context).push(MaterialPageRoute( + builder: (c) => UserChannelScreen(owner: item.author))); } } @@ -106,12 +106,15 @@ class _HomeScreenState extends State { return Scaffold( appBar: AppBar( title: Text(widget.title), - // actions: [ - // IconButton(onPressed: (){ - // var route = MaterialPageRoute(builder: (context) => const SearchScreen()); - // Navigator.of(context).push(route); - // }, icon: const Icon(Icons.search)) - // ], + actions: [ + IconButton( + onPressed: () { + var route = MaterialPageRoute( + builder: (context) => const SearchScreen()); + Navigator.of(context).push(route); + }, + icon: const Icon(Icons.search)) + ], ), body: _screen(), drawer: widget.showDrawer ? const DrawerScreen() : null, diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index d8fdb8ce..394bd561 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -1,11 +1,11 @@ +import 'dart:convert'; + import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/home_screen_feed_models/hive_payout_response.dart'; -import 'package:acela/src/utils/form_factor.dart'; import 'package:flutter/material.dart'; -import 'custom_circle_avatar.dart'; -import '../utils/form_factor.dart'; import 'package:http/http.dart' as http; -import 'dart:convert'; + +import 'custom_circle_avatar.dart'; class ListTileVideo extends StatelessWidget { const ListTileVideo({ @@ -53,9 +53,9 @@ class ListTileVideo extends StatelessWidget { Container( padding: const EdgeInsets.all(5), decoration: const BoxDecoration( - borderRadius: BorderRadiusDirectional.all(Radius.circular(10)), - color: Colors.blueGrey - ), + borderRadius: + BorderRadiusDirectional.all(Radius.circular(10)), + color: Colors.blueGrey), child: Text('\$ $value'), ), const SizedBox(height: 5), @@ -63,7 +63,7 @@ class ListTileVideo extends StatelessWidget { ), const Spacer(), ], - ) + ), ); } @@ -86,24 +86,24 @@ class ListTileVideo extends StatelessWidget { Widget _hivePayoutLoader() { return FutureBuilder( - builder: (context, snapshot) { - if (snapshot.hasData) { - var data = snapshot.data as HivePayoutResponse; - if (data.result.pendingPayoutValue == "0.000 HBD") { - var total = double - .parse(data.result.totalPayoutValue.replaceAll(' HBD', '')); - var curator = double - .parse(data.result.curatorPayoutValue.replaceAll(' HBD', '')); - return _amount(total + curator); - } else { - var value = double - .parse(data.result.pendingPayoutValue.replaceAll(' HBD', '')); - return _amount(value); - } + builder: (context, snapshot) { + if (snapshot.hasData) { + var data = snapshot.data as HivePayoutResponse; + if (data.result.pendingPayoutValue == "0.000 HBD") { + var total = double.parse( + data.result.totalPayoutValue.replaceAll(' HBD', '')); + var curator = double.parse( + data.result.curatorPayoutValue.replaceAll(' HBD', '')); + return _amount(total + curator); } else { - return Container(); + var value = double.parse( + data.result.pendingPayoutValue.replaceAll(' HBD', '')); + return _amount(value); } - }, + } else { + return Container(); + } + }, future: _futureHivePayout(), ); } @@ -131,7 +131,7 @@ class ListTileVideo extends StatelessWidget { }, ), ), - // _hivePayoutLoader(), + _hivePayoutLoader(), ], ), Container( diff --git a/pubspec.yaml b/pubspec.yaml index ef65abd6..7f161ae1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+6 +version: 1.0.0+9 environment: sdk: ">=2.15.1 <3.0.0" From 26629c9b865dd848e46718114a5f8126c83aab4d Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 5 Apr 2022 05:20:57 +0530 Subject: [PATCH 055/466] about us integrated --- .DS_Store | Bin 6148 -> 6148 bytes .flutter-plugins-dependencies | 2 +- .packages | 2 +- lib/src/screens/about/about_faq.dart | 50 ++++++++++ lib/src/screens/about/about_home_screen.dart | 27 ++++-- lib/src/screens/about/about_us.dart | 91 ++++++++++++++++++ .../screens/drawer_screen/drawer_screen.dart | 7 +- 7 files changed, 164 insertions(+), 15 deletions(-) create mode 100644 lib/src/screens/about/about_faq.dart create mode 100644 lib/src/screens/about/about_us.dart diff --git a/.DS_Store b/.DS_Store index 22c7280d4c20d01af6e3b82503823e85c968543a..77c2f376ab916db39babb2738c892e1e3b923f6d 100644 GIT binary patch delta 81 zcmZoMXfc?O$h;$|VDm%f<&2ZLnZy`(OlD;+RF|l(HZ?HNQ7|$ws?|}bwzM$QQ82SG ludU_e5LMQ<4vNpt$<52}nmmtLp0RuLO(tE|&Fmb1`2qa07@+_F delta 80 zcmZoMXfc?O$heRHZeERQ7|*A)lsOnG&0apFtIeM kt>xqpRo1r-iqFo;&CBncJfB&fv1{`!CSBIeY#jgi0q4UQW&i*H diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 34543e9a..c569dbda 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-03-27 12:59:20.712037","version":"2.10.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-04-04 21:43:06.480646","version":"2.10.4"} \ No newline at end of file diff --git a/.packages b/.packages index c70d7150..e27e345d 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-03-27 12:49:44.177171. +# Generated by pub on 2022-04-04 21:42:54.814554. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ diff --git a/lib/src/screens/about/about_faq.dart b/lib/src/screens/about/about_faq.dart new file mode 100644 index 00000000..3bf03266 --- /dev/null +++ b/lib/src/screens/about/about_faq.dart @@ -0,0 +1,50 @@ +import 'package:acela/src/screens/about/about_us.dart'; +import 'package:flutter/material.dart'; + +class AboutFaqScreen extends StatelessWidget { + const AboutFaqScreen({Key? key}) : super(key: key); + static List elements = [ + AboutUsElement( + title: "What is 3Speak?", + subtitle: + "3Speak is a place where content creators directly own their onsite assets and their communities. Using blockchain technology, the ownership of these assets and communities are intrinsic to the creator and the user, not 3 Speak. They are therefore transferable to other apps that use blockchain technology. This means that if we do not serve the community and creators in the best possible way, they can take the assets they have generated and move them to another app. The result is that 3Speak is censorship resistant, cannot take your assets away or delete your communities.\n\nOur policy is that the ability to be offensive is the bedrock of Freedom of Speech, and in turn Freedom of Speech protects societies from descending into chaos and civil war. Everyone has the right to their opinions, no matter how offensive some other people may find it (as long as it's not inciting violence or illegal of course). We especially welcome those talking about cryptocurrency and other emerging technologies which are threats to the establishment. Many of these content creators are being silenced because rich and powerful organisations do not want to be challenged. But we believe in Freedom of choice too!"), + AboutUsElement( + title: "Why am I not upvoted by 3Speak?", + subtitle: + "3Speak will vote at our own discretion and do not follow any specific criteria. The best way to attract our attention is to upload high-quality content and draw audiences and communities to 3speak."), + AboutUsElement( + title: "Why are some of my videos missing from the new feed?", + subtitle: + "We allow you to upload as many videos as you want! This means that sometimes one user could fill up feeds with just their content, to combat this, we limit the videos by any one creator that can be displayed per load."), + AboutUsElement( + title: "What are the guidelines?", + subtitle: + "We believe Freedom of Speech is absolute. As outlined above, there are some instances where we would have to restrict content, but for clarity here are 3speak's policies on various subjects:\n\nWe fully support your right to be offensive as long as it does not violate any of our terms (see below).\n\nCRITICISING RELIGION, BELIEFS, GROUPS, PEOPLE:\n\nSWEARING AND PROFANITY: (slander not allowed)\n\nOFFENSIVE JOKES: (If you are making a joke which could be construed as something illegal or slanderous, it might be a good idea to make it clear. As long as you aren't calling for people to be killed or harmed in any way.)\n\nALTERNATIVE POLITICS / CONSPIRACIES / CRITICIZING GOVERNMENTS & WORLD LEADERS:\n\nPSEUDONYMS: \n\nCALLING FOR OR INCITEMENT TO VIOLENCE: \n\nSHOWING OF EXCESSIVE GORE OR PORN:"), + AboutUsElement( + title: "How do I become a content creator?", + subtitle: + "The quickest way to get a hive account is to press the \"Sign up\" button in the navigation panel and follow the instructions. (dont loose your keys!).\nNext you will need to log in with your hive account and click on the \"creator studio\" / upload.\nYou're all set up and ready to go!"), + AboutUsElement( + title: "How do I earn rewards for commenting?", + subtitle: + "In order to earn rewards, you need a Hive blockchain account. There are a few ways to get a Hive account:\n\n1. Get one for free from Hive (https://signup.hive.io). This can take some time to get approved however.\n2. Purchase a Hive user guide, which comes with a free, instant Hive account here. However, with value adding, useful or articulate commenting you should be able to earn this back in a few days, or after uploading a couple of videos.\n3. Get another Hive user who can claim accounts to give one to you\n\nOnce you have an account, you need to login with Hivesigner. You will need to provide your ACTIVE key ONLY on the first login. Then you can post comments which can earn.\n\nIf you want to comment without earning cryptocurrency rewards, you can simply login with email or via your facebook, google, twitter or instagram accounts."), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('FREQUENTLY ASKED QUESTIONS'), + ), + body: ListView.separated( + itemBuilder: (c, i) { + return ListTile( + title: Text(elements[i].title), + subtitle: Text(elements[i].subtitle), + ); + }, + separatorBuilder: (c, i) => const Divider(), + itemCount: elements.length), + ); + } +} diff --git a/lib/src/screens/about/about_home_screen.dart b/lib/src/screens/about/about_home_screen.dart index 1aa27d21..14f2f58d 100644 --- a/lib/src/screens/about/about_home_screen.dart +++ b/lib/src/screens/about/about_home_screen.dart @@ -1,6 +1,9 @@ +import 'package:acela/src/screens/about/about_faq.dart'; +import 'package:acela/src/screens/about/about_us.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:url_launcher/url_launcher.dart'; class AboutHomeScreen extends StatelessWidget { const AboutHomeScreen({Key? key}) : super(key: key); @@ -17,63 +20,69 @@ class AboutHomeScreen extends StatelessWidget { leading: const Icon(Icons.info_outline), title: const Text('About us'), onTap: () { - + var screen = const AboutUsScreen(); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); }, ), ListTile( leading: const FaIcon(FontAwesomeIcons.question), title: const Text('FAQ'), onTap: () { - + var screen = const AboutFaqScreen(); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); }, ), ListTile( leading: const FaIcon(FontAwesomeIcons.twitter), title: const Text('Follow us on Twitter'), onTap: () { - + launch( + 'https://twitter.com/3speakonline?utm_source=3speak.tv.acela'); }, ), ListTile( leading: const FaIcon(FontAwesomeIcons.telegram), title: const Text('Join us on Telegram'), onTap: () { - + launch('https://t.me/threespeak?utm_source=3speak.tv.acela'); }, ), ListTile( leading: const FaIcon(FontAwesomeIcons.discord), title: const Text('Join us on Discord'), onTap: () { - + launch('https://discord.me/3speak?utm_source=3speak.tv.acela'); }, ), ListTile( leading: const FaIcon(FontAwesomeIcons.blog), title: const Text('Visit blog - hive.blog/@threespeak'), onTap: () { - + launch('https://hive.blog/@threespeak'); }, ), ListTile( leading: const Icon(Icons.web), title: const Text('Visit website - spk.network'), onTap: () { - + launch('https://spk.network/'); }, ), ListTile( leading: const Icon(Icons.web), title: const Text('Visit website - 3speak.tv'), onTap: () { - + launch('https://3speak.tv/'); }, ), ListTile( leading: const Icon(Icons.picture_as_pdf), title: const Text('Terms of service'), onTap: () { - + launch( + 'https://threespeakvideo.b-cdn.net/static/terms_of_service.pdf'); }, ), ListTile( diff --git a/lib/src/screens/about/about_us.dart b/lib/src/screens/about/about_us.dart new file mode 100644 index 00000000..b8ee3070 --- /dev/null +++ b/lib/src/screens/about/about_us.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; + +class AboutUsElement { + String title; + String subtitle; + + AboutUsElement({required this.title, required this.subtitle}); +} + +class AboutUsScreen extends StatelessWidget { + const AboutUsScreen({Key? key}) : super(key: key); + static List elements = [ + AboutUsElement( + title: "3SPEAK, PROTECT YOUR CONTENT, TOKENISE YOUR COMMUNITY", + subtitle: + "3Speak is a place where content creators directly own their onsite assets and their communities. Using blockchain technology, the ownership of these assets and communities are intrinsic to the creator and the user, not 3 Speak. They are therefore transferable to other apps that use blockchain technology. This means that if we do not serve the community and creators in the best possible way, they can take the assets they have generated and move them to another app. The result is that 3Speak is censorship resistant, cannot take your assets away or delete your communities."), + AboutUsElement( + title: "REWARDS", + subtitle: + "By using the platform, users get rewarded in Hive tokens and can receive donations in our proprietary Speak token. The more of these tokens you hold, the more privileges you have in the eco system. Additionally, the more tokens you hold, the more say you have over the governance of the platform and where it goes in future."), + AboutUsElement( + title: "P2P", + subtitle: + "The blockchain technology that the site uses ensures that content creators have true P2P connections to their user base, without any middle parties."), + AboutUsElement( + title: "TOKENISATION", + subtitle: + "Content creators can also easily create their own tokens, market places, stake driven rewards and economies to back their communities"), + AboutUsElement( + title: "FREE SPEECH", + subtitle: + "Our policy is that the ability to be offensive is the bedrock of Freedom of Speech, and in turn Freedom of Speech protects societies from descending into chaos and civil war. Everyone has the right to their opinions, no matter how offensive some other people may find it (as long as it's not inciting violence or illegal of course). We especially welcome those talking about cryptocurrency and other emerging technologies which are threats to the establishment. Many of these content creators are being silenced because rich and powerful organisations do not want to be challenged. But we believe in Freedom of choice too!"), + AboutUsElement( + title: "CITIZEN JOURNALISM", + subtitle: + "We also encourage citizen journalists to join us too, and post the kind of content which is often ignored. We believe that citizen journalists are the future, and we invite them to come and join our Citizen Journalist Tag and Community"), + AboutUsElement( + title: "George Orwell", + subtitle: + "If liberty means anything at all, it means the right to tell people what they do not want to hear."), + AboutUsElement( + title: "Voltaire", + subtitle: + "I disapprove of what you say, but I will defend to the death your right to say it."), + AboutUsElement( + title: "Philip Sharp", + subtitle: + "The right to free speech and the unrealistic expectation to never be offended can not coexist."), + AboutUsElement( + title: "Marshall Lumsden", + subtitle: + "At no time is freedom of speech more precious than when a man hits his thumb with a hammer."), + AboutUsElement( + title: "Alan Dershowitz", + subtitle: + "Freedom of speech means freedom for those who you despise, and freedom to express the most despicable views. It also means that the government cannot pick and choose which expressions to authorize and which to prevent."), + AboutUsElement( + title: "Anna Quindlen", + subtitle: + "Ignorant free speech often works against the speaker. That is one of several reasons why it must be given rein instead of suppressed."), + AboutUsElement( + title: "Brad Thor", + subtitle: "Freedom of speech includes the freedom to offend people."), + AboutUsElement( + title: "Newton Lee", + subtitle: + "There is a fine line between free speech and hate speech. Free speech encourages debate whereas hate speech incites violence."), + AboutUsElement( + title: "Hugo L. Black", + subtitle: + "Freedom of speech means that you shall not do something to people either for the views they have, or the views they express, or the words they speak or write."), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('ABOUT 3SPEAK'), + ), + body: ListView.separated( + itemBuilder: (c, i) { + return ListTile( + title: Text(elements[i].title), + subtitle: Text(elements[i].subtitle), + ); + }, + separatorBuilder: (c, i) => const Divider(), + itemCount: elements.length), + ); + } +} diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index eea55789..108afad6 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -3,7 +3,6 @@ import 'package:acela/src/screens/about/about_home_screen.dart'; import 'package:acela/src/screens/communities_screen/communities_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; -import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -121,9 +120,9 @@ class DrawerScreen extends StatelessWidget { ], ), onTap: () { - // var screen = const AboutHomeScreen(); - // var route = MaterialPageRoute(builder: (_) => screen); - // Navigator.of(context).push(route); + var screen = const AboutHomeScreen(); + var route = MaterialPageRoute(builder: (_) => screen); + Navigator.of(context).push(route); }, ), ); From 7d62980afbda08cd1310ce0179bb19695878a183 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 7 Apr 2022 14:55:31 +0530 Subject: [PATCH 056/466] version bump. --- .flutter-plugins-dependencies | 2 +- .packages | 2 +- ios/Runner.xcodeproj/project.pbxproj | 12 ++++++------ pubspec.yaml | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index c569dbda..2b9009ce 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-04-04 21:43:06.480646","version":"2.10.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-04-05 05:22:16.397001","version":"2.10.4"} \ No newline at end of file diff --git a/.packages b/.packages index e27e345d..8f2fb9bb 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-04-04 21:42:54.814554. +# Generated by pub on 2022-04-05 05:21:25.969369. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index b1425740..314dd9f4 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -332,7 +332,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -361,7 +361,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -408,7 +408,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -466,7 +466,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -497,7 +497,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -521,7 +521,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/pubspec.yaml b/pubspec.yaml index 7f161ae1..1e4cafd9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+9 +version: 1.0.0+10 environment: sdk: ">=2.15.1 <3.0.0" From 98192628d00a5f2352ef3467d32cea44e2521702 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 25 Apr 2022 08:28:10 +0530 Subject: [PATCH 057/466] removed web-app code. bug fix 1. Name should be clickable on video-listing. --- .DS_Store | Bin 6148 -> 6148 bytes .firebase/hosting.YnVpbGQvd2Vi.cache | 22 --- .firebase/hosting.d2Vi.cache | 11 -- .firebaserc | 5 - .flutter-plugins | 14 +- .flutter-plugins-dependencies | 2 +- .gitignore | 4 +- .idea/.gitignore | 3 - .idea/.name | 1 - .idea/Android-App.iml | 22 +++ .idea/codeStyles/Project.xml | 117 ---------------- .idea/codeStyles/codeStyleConfig.xml | 5 - .idea/libraries/Dart_Packages.xml | 104 +++++++-------- .idea/libraries/Flutter_Plugins.xml | 22 +-- .idea/libraries/KotlinJavaRuntime.xml | 15 --- .idea/misc.xml | 12 -- .idea/modules.xml | 3 +- .idea/runConfigurations/main_dart.xml | 7 - .metadata | 10 -- .packages | 50 +++---- analysis_options.yaml | 29 ---- android/.idea/gradle.xml | 6 +- .../-1065946935/android.video_player.iml | 97 -------------- android/app/build.gradle | 3 +- firebase.json | 16 --- .../community_details_screen.dart | 5 +- .../home_screen/home_screen_widgets.dart | 3 +- lib/src/screens/search/search_screen.dart | 5 +- .../user_channel_videos.dart | 10 +- .../video_details_screen.dart | 7 +- lib/src/widgets/controls_overlay.dart | 125 ------------------ lib/src/widgets/list_tile_video.dart | 20 ++- pubspec.lock | 48 +++---- web/favicon.png | Bin 3513 -> 0 bytes web/icons/Icon-192.png | Bin 23416 -> 0 bytes web/icons/Icon-512.png | Bin 103955 -> 0 bytes web/icons/Icon-maskable-192.png | Bin 23414 -> 0 bytes web/icons/Icon-maskable-512.png | Bin 103953 -> 0 bytes web/index.html | 105 --------------- web/manifest.json | 35 ----- 40 files changed, 180 insertions(+), 763 deletions(-) delete mode 100644 .firebase/hosting.YnVpbGQvd2Vi.cache delete mode 100644 .firebase/hosting.d2Vi.cache delete mode 100644 .firebaserc delete mode 100644 .idea/.gitignore delete mode 100644 .idea/.name create mode 100644 .idea/Android-App.iml delete mode 100644 .idea/codeStyles/Project.xml delete mode 100644 .idea/codeStyles/codeStyleConfig.xml delete mode 100644 .idea/libraries/KotlinJavaRuntime.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/runConfigurations/main_dart.xml delete mode 100644 .metadata delete mode 100644 analysis_options.yaml delete mode 100644 android/.idea/modules/-1065946935/android.video_player.iml delete mode 100644 firebase.json delete mode 100644 lib/src/widgets/controls_overlay.dart delete mode 100644 web/favicon.png delete mode 100644 web/icons/Icon-192.png delete mode 100644 web/icons/Icon-512.png delete mode 100644 web/icons/Icon-maskable-192.png delete mode 100644 web/icons/Icon-maskable-512.png delete mode 100644 web/index.html delete mode 100644 web/manifest.json diff --git a/.DS_Store b/.DS_Store index 77c2f376ab916db39babb2738c892e1e3b923f6d..aa38b5f10ddb820cfa227fe34955814c679270da 100644 GIT binary patch delta 69 zcmZoMXfc=|#>B`mu~2NHo+2aD#DLwC4MbQb^D{l!e1ln^W%CE-r;MA~Iruq%iZ(xF Y{?0s^U&NAw0SFiw7??H(h-_g70K{(+o&W#< delta 158 zcmZoMXfc=|#>B)qu~2NHo+2a5#DLw4m>3yZCi5^p7iMNCXGmp8N-8fdNXp4iVqjp{ zIa!IZP(!l1+StfUN5RnCvQ|f-+R(_ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 4bec4ea8..00000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index a55e7a17..00000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index bbf0ef04..c7ffc9f5 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -5,21 +5,14 @@ - - - - - - - - @@ -47,7 +40,7 @@ - @@ -61,21 +54,21 @@ - - - @@ -96,7 +89,7 @@ - @@ -124,7 +117,7 @@ - @@ -180,7 +173,7 @@ - @@ -208,7 +201,7 @@ - @@ -222,7 +215,7 @@ - @@ -257,7 +250,7 @@ - @@ -355,7 +348,7 @@ - @@ -376,7 +369,7 @@ - @@ -509,7 +502,7 @@ - @@ -530,14 +523,14 @@ - - @@ -614,7 +607,7 @@ - @@ -684,35 +677,35 @@ - - - - - @@ -775,7 +768,7 @@ - @@ -789,23 +782,23 @@ - - + + - + - - - + + + - + - + @@ -813,17 +806,17 @@ - + - + - + - + @@ -835,10 +828,10 @@ - + - + @@ -857,10 +850,10 @@ - + - - + + @@ -871,7 +864,7 @@ - + @@ -881,11 +874,11 @@ - - - - - + + + + + @@ -894,13 +887,12 @@ - + - diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index a5891bbf..03197b44 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,26 +1,26 @@ + + - + + + - + + + + - - - - - - - - - + + diff --git a/.idea/libraries/KotlinJavaRuntime.xml b/.idea/libraries/KotlinJavaRuntime.xml deleted file mode 100644 index 2b96ac4b..00000000 --- a/.idea/libraries/KotlinJavaRuntime.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 6e5825fe..00000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 81617e7d..b8bc9936 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,8 +2,7 @@ - - + \ No newline at end of file diff --git a/.idea/runConfigurations/main_dart.xml b/.idea/runConfigurations/main_dart.xml deleted file mode 100644 index dcb3d7b2..00000000 --- a/.idea/runConfigurations/main_dart.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/.metadata b/.metadata deleted file mode 100644 index fd70cabc..00000000 --- a/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 77d935af4db863f6abd0b9c31c7e6df2a13de57b - channel: stable - -project_type: app diff --git a/.packages b/.packages index 8f2fb9bb..ae461d37 100644 --- a/.packages +++ b/.packages @@ -3,24 +3,24 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-04-05 05:21:25.969369. -_fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-36.0.0/lib/ -analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-3.3.1/lib/ +# Generated by pub on 2022-04-25 08:13:46.316478. +_fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ +analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ boolean_selector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/ -build:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build-2.2.1/lib/ +build:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build-2.3.0/lib/ build_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_config-1.0.0/lib/ -build_daemon:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_daemon-3.0.1/lib/ -build_resolvers:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_resolvers-2.0.6/lib/ -build_runner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner-2.1.8/lib/ +build_daemon:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_daemon-3.1.0/lib/ +build_resolvers:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_resolvers-2.0.8/lib/ +build_runner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner-2.1.10/lib/ build_runner_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner_core-7.2.3/lib/ built_collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_collection-5.1.1/lib/ -built_value:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_value-8.1.4/lib/ +built_value:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_value-8.2.0/lib/ characters:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib/ charcode:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib/ checked_yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/checked_yaml-2.0.1/lib/ -chewie:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/chewie-1.3.1/lib/ +chewie:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/chewie-1.3.2/lib/ clock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib/ code_builder:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/code_builder-4.1.0/lib/ collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0/lib/ @@ -28,18 +28,18 @@ convert:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ crypto:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.1/lib/ csslib:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.17.1/lib/ cupertino_icons:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.4/lib/ -dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.2/lib/ +dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.3/lib/ fake_async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0/lib/ ffi:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.1.2/lib/ file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib/ -firebase_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.13.1/lib/ +firebase_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/lib/ firebase_core_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_platform_interface-4.2.5/lib/ -firebase_core_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.1/lib/ +firebase_core_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/lib/ fixnum:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fixnum-1.0.0/lib/ flutter:file:///Applications/flutter/flutter/packages/flutter/lib/ flutter_dotenv:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_dotenv-5.0.2/lib/ flutter_lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib/ -flutter_markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_markdown-0.6.9/lib/ +flutter_markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_markdown-0.6.10/lib/ flutter_test:file:///Applications/flutter/flutter/packages/flutter_test/lib/ flutter_web_plugins:file:///Applications/flutter/flutter/packages/flutter_web_plugins/lib/ font_awesome_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/font_awesome_flutter-9.2.0/lib/ @@ -53,10 +53,10 @@ http_parser:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang. io:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/io-1.0.3/lib/ js:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3/lib/ json_annotation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_annotation-4.4.0/lib/ -json_serializable:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_serializable-6.1.5/lib/ +json_serializable:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_serializable-6.1.6/lib/ lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib/ logging:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/logging-1.0.2/lib/ -markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/markdown-4.0.1/lib/ +markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/markdown-5.0.0/lib/ matcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.11/lib/ material_color_utilities:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.3/lib/ meta:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib/ @@ -75,11 +75,11 @@ share_plus_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dart share_plus_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_platform_interface-2.1.0/lib/ share_plus_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/lib/ share_plus_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-2.0.3/lib/ -shelf:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.2.0/lib/ +shelf:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.3.0/lib/ shelf_web_socket:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-1.0.1/lib/ sky_engine:file:///Applications/flutter/flutter/bin/cache/pkg/sky_engine/lib/ -source_gen:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_gen-1.2.1/lib/ -source_helper:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_helper-1.3.1/lib/ +source_gen:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_gen-1.2.2/lib/ +source_helper:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_helper-1.3.2/lib/ source_span:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.1/lib/ stack_trace:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib/ stream_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0/lib/ @@ -90,7 +90,7 @@ test_api:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org timeago:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timeago-3.2.2/lib/ timing:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timing-1.0.0/lib/ typed_data:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib/ -url_launcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.20/lib/ +url_launcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.1.0/lib/ url_launcher_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/lib/ url_launcher_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/lib/ url_launcher_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/lib/ @@ -100,11 +100,11 @@ url_launcher_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dart url_launcher_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/lib/ vector_math:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.1/lib/ very_good_analysis:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/very_good_analysis-2.4.0/lib/ -video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.3.0/lib/ -video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.1/lib/ -video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.1/lib/ -video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.0/lib/ -video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.7/lib/ +video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.4.0/lib/ +video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/lib/ +video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.2/lib/ +video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.2/lib/ +video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/lib/ video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/lib/ wakelock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/lib/ wakelock_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/lib/ @@ -113,6 +113,6 @@ wakelock_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang wakelock_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_windows-0.2.0/lib/ watcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/watcher-1.0.1/lib/ web_socket_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.1.0/lib/ -win32:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/win32-2.4.1/lib/ +win32:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/win32-2.5.1/lib/ yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/yaml-3.1.0/lib/ acela:lib/ diff --git a/analysis_options.yaml b/analysis_options.yaml deleted file mode 100644 index 61b6c4de..00000000 --- a/analysis_options.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml index 1c4cf4dc..03ca2859 100644 --- a/android/.idea/gradle.xml +++ b/android/.idea/gradle.xml @@ -9,7 +9,11 @@ bEkjWNX6aqvk>`=O^zvi0gTrtS`|vGSgBie0NIL~boX zVDu?L@%h`ZTPgbaeJ9CtnwK38698^1b z2h9~JoT}ftemFDw-2=&8o@Obk0}-=ghWYNUb{S2T>?g+XS=qtnU3p4Hu0|R$qGJA< zB*H0K_69&obELJ^C)se|oRn7vtizwdWc3AM!lRI5O`Mv9m%$PJJ6;KS6}hPfRfonb=x%%a^VBqi&0~y(^BFnh%Kh;2>q~#gRQV+z z?tb_z@t(@?^wAK*g`1o4{gmN@HS)#t4DRcm*y@8;%sp_nj%-yU>~cShvP+J2Ray8fu%}9>h#VAX`c%YtLo*On-bNd{o3C zJ)(o1{)$9=J%2sra+tgesABhg7X%sIt|l^jSZnFBHN{We!4d)eOSGpq*995tkKjyjcow*B5c&c<# zZWa!a9qF>auu-W>2XEG_R<0zgGGc^U^n~{4Dn_>NYlpySpTo#$pA~kr?2nc7#U;Ak zZY_Lk)gsl9y{Nw4X$S7MlX~yG9~!4Wcll}Mkl()Cg-T0^r0|Rlq)eJ?EMwYLI=AqE zcIYZbRvtyNSZu#kGS}y|HJ~h-01vKE7uce7)+qA$(`5$fhQeM$xn<gYXz?7x7D1v8!pE zv!Ebva>Hfp>iu*2hWo*&iEuKX;*%bEc)JZhWIrSN+*V;XAd-!}+z! zWZ@)&0gl{8b_ct=Y71L*sKNR<&BQ=W$_eAyuUWSCX@?l`JAMf4y6jZofWCH+iE<@^XC_hS%8nxrK&wzZ5OL@HWlgj^N%U auqY4K#AUtd25Jabgd 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%0ArSuMfYdR~xWDN6vl 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 z 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%0DoKY9=<*9SRJ~eL6 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 Q3OHOBFI+aQFm{dk4*`)r#Q*>R diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png deleted file mode 100644 index aa6e10ac0ca4e7d7564c32cd4d4670d9c2524cbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23414 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 z 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 - - - - - - - - - - - - - - - - - - - acela - - - - - - - - diff --git a/web/manifest.json b/web/manifest.json deleted file mode 100644 index 4918763a..00000000 --- a/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "acela", - "short_name": "acela", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "3Speak App", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} From 7586d1d670305a2b95bbb13008521658f2ab7110 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 25 Apr 2022 09:37:30 +0530 Subject: [PATCH 058/466] Bug fixes. --- .flutter-plugins-dependencies | 2 +- .../community_details_screen.dart | 3 +- .../home_screen/home_screen_widgets.dart | 1 + lib/src/screens/search/search_screen.dart | 1 + .../user_channel_profile.dart | 16 +++--- .../user_channel_videos.dart | 1 + .../video_details_comments.dart | 4 +- .../video_details_info.dart | 12 ++--- .../video_details_screen.dart | 53 +++++++++---------- lib/src/widgets/list_tile_video.dart | 26 ++++----- 10 files changed, 61 insertions(+), 58 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 35d8491a..debdda70 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-04-25 08:23:10.665188","version":"2.10.5"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-04-25 09:33:00.722239","version":"2.10.5"} \ No newline at end of file diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index 1f9e29e6..5d749af9 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -107,6 +107,7 @@ class _CommunityDetailScreenState extends State }, user: item.author, permlink: item.permlink, + shouldResize: true, ); } @@ -163,7 +164,7 @@ class _CommunityDetailScreenState extends State return Markdown( data: Utilities.removeAllHtmlTags(markDown), onTapLink: (text, url, title) { - launch(url!); + launchUrl(Uri.parse(url ?? 'https://google.com')); }, ); } diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index e6b58c63..eefdb65f 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -28,6 +28,7 @@ class HomeScreenWidgets { }, user: item.author, permlink: item.permlink, + shouldResize: true, ); } diff --git a/lib/src/screens/search/search_screen.dart b/lib/src/screens/search/search_screen.dart index ae4178a6..a81101e8 100644 --- a/lib/src/screens/search/search_screen.dart +++ b/lib/src/screens/search/search_screen.dart @@ -110,6 +110,7 @@ class _SearchScreenState extends State { }, user: item.author, permlink: item.permlink, + shouldResize: false, ), onTap: () { var vm = diff --git a/lib/src/screens/user_channel_screen/user_channel_profile.dart b/lib/src/screens/user_channel_screen/user_channel_profile.dart index ec5c8e16..790c0879 100644 --- a/lib/src/screens/user_channel_screen/user_channel_profile.dart +++ b/lib/src/screens/user_channel_screen/user_channel_profile.dart @@ -1,21 +1,21 @@ import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/user_profile/request/user_profile_request.dart'; +import 'package:acela/src/models/user_profile/response/user_profile.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; -import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:http/http.dart' as http; -import 'package:acela/src/models/user_profile/request/user_profile_request.dart'; -import 'package:acela/src/models/user_profile/response/user_profile.dart'; -import 'package:url_launcher/link.dart'; import 'package:url_launcher/url_launcher.dart'; class UserChannelProfileWidget extends StatefulWidget { - const UserChannelProfileWidget({Key? key, required this.owner}) : super(key: key); + const UserChannelProfileWidget({Key? key, required this.owner}) + : super(key: key); final String owner; @override - State createState() => _UserChannelProfileWidgetState(); + State createState() => + _UserChannelProfileWidgetState(); } class _UserChannelProfileWidgetState extends State @@ -52,11 +52,11 @@ class _UserChannelProfileWidgetState extends State padding: const EdgeInsets.all(3), data: Utilities.removeAllHtmlTags(markDown), onTapLink: (text, url, title) { - launch(url!); + launchUrl(Uri.parse(url ?? 'https://google.com')); }, ); } - + String _generateMarkDown(UserProfileResponse data) { return "![cover image](${data.result.metadata.profile.coverImage})\n## Bio:\n${data.result.metadata.profile.about}\n\n\n## Created At:\n${Utilities.parseAndFormatDateTime(data.result.created)}\n\n## Last Seen At:\n${Utilities.parseAndFormatDateTime(data.result.active)}\n\n## Total Hive Posts:\n${data.result.postCount}\n\n## Hive Reputation:\n${data.result.reputation}\n\n## Location:\n${data.result.metadata.profile.location.isEmpty ? 'None' : data.result.metadata.profile.location}\n\n## Website:\n${data.result.metadata.profile.website.isEmpty ? 'None' : data.result.metadata.profile.website}"; } diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart index 317903d3..bb81d549 100644 --- a/lib/src/screens/user_channel_screen/user_channel_videos.dart +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -52,6 +52,7 @@ class _UserChannelVideosState extends State }, user: item.author, permlink: item.permlink, + shouldResize: true, ); } diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart index 09c15fe4..f0ce431b 100644 --- a/lib/src/screens/video_details_screen/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -5,9 +5,9 @@ import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:http/http.dart' as http; import 'package:timeago/timeago.dart' as timeago; import 'package:url_launcher/url_launcher.dart'; -import 'package:http/http.dart' as http; class VideoDetailsComments extends StatefulWidget { const VideoDetailsComments( @@ -84,7 +84,7 @@ class _VideoDetailsCommentsState extends State { data: Utilities.removeAllHtmlTags(body), shrinkWrap: true, onTapLink: (text, url, title) { - launch(url!); + launchUrl(Uri.parse(url ?? 'https://google.com')); }, ), Container(margin: const EdgeInsets.only(bottom: 10)), diff --git a/lib/src/screens/video_details_screen/video_details_info.dart b/lib/src/screens/video_details_screen/video_details_info.dart index c14d0d63..55e3e752 100644 --- a/lib/src/screens/video_details_screen/video_details_info.dart +++ b/lib/src/screens/video_details_screen/video_details_info.dart @@ -2,11 +2,12 @@ import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; -import 'package:url_launcher/url_launcher.dart'; import 'package:timeago/timeago.dart' as timeago; +import 'package:url_launcher/url_launcher.dart'; class VideoDetailsInfoWidget extends StatelessWidget { - const VideoDetailsInfoWidget({Key? key, required this.details}) : super(key: key); + const VideoDetailsInfoWidget({Key? key, required this.details}) + : super(key: key); final VideoDetails details; Widget header(BuildContext context) { @@ -18,8 +19,7 @@ class VideoDetailsInfoWidget extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(details.title, - style: Theme.of(context).textTheme.bodyLarge), + Text(details.title, style: Theme.of(context).textTheme.bodyLarge), const SizedBox(height: 3), Text(string, style: Theme.of(context).textTheme.bodySmall), ], @@ -33,7 +33,7 @@ class VideoDetailsInfoWidget extends StatelessWidget { padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10), data: Utilities.removeAllHtmlTags(markDown), onTapLink: (text, url, title) { - launch(url!); + launchUrl(Uri.parse(url ?? 'https://google.com')); }, ); } @@ -42,7 +42,7 @@ class VideoDetailsInfoWidget extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(details.owner), + title: Text(details.title), ), body: SafeArea( child: Stack( diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index ba1dc7e7..f2dc96d6 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -62,35 +62,20 @@ class _VideoDetailsScreenState extends State { return Markdown( data: Utilities.removeAllHtmlTags(markDown), onTapLink: (text, url, title) { - launch(url!); + launchUrl(Uri.parse(url ?? 'https://google.com')); }, ); } // video description - Widget titleAndSubtitleCommon(VideoDetails details, bool fullScreen) { + Widget titleAndSubtitleCommon(VideoDetails details) { String string = "📆 ${timeago.format(DateTime.parse(details.created))} · ▶ ${details.views} views · 👥 ${details.community}"; - var fullScreenButton = IconButton( - onPressed: () { - var route = MaterialPageRoute(builder: (context) { - return VideoDetailsInfoWidget(details: details); - }); - Navigator.of(context).push(route); - }, - icon: const Icon(Icons.fullscreen), - ); - var closeButton = IconButton( - onPressed: () { - Navigator.of(context).pop(); - }, - icon: const Icon(Icons.close), - ); var downIcon = const Icon(Icons.arrow_drop_down_outlined); List children = [ Expanded( child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(details.title, style: Theme.of(context).textTheme.bodyLarge), const SizedBox(height: 3), @@ -99,12 +84,7 @@ class _VideoDetailsScreenState extends State { ), ), ]; - if (fullScreen) { - children.add(fullScreenButton); - children.add(closeButton); - } else { - children.add(downIcon); - } + children.add(downIcon); return Container( margin: const EdgeInsets.all(10), child: Row( @@ -126,10 +106,26 @@ class _VideoDetailsScreenState extends State { child: Stack( children: [ Container( - margin: const EdgeInsets.only(top: 70), + margin: const EdgeInsets.only(top: 55), child: descriptionMarkDown(details.description), ), - titleAndSubtitleCommon(details, true), + Container( + height: 55, + child: AppBar( + title: Text(details.title), + actions: [ + IconButton( + onPressed: () { + var route = MaterialPageRoute(builder: (context) { + return VideoDetailsInfoWidget(details: details); + }); + Navigator.of(context).push(route); + }, + icon: const Icon(Icons.fullscreen), + ) + ], + ), + ) ], ), ); @@ -140,7 +136,7 @@ class _VideoDetailsScreenState extends State { // video description Widget titleAndSubtitle(VideoDetails details) { return InkWell( - child: titleAndSubtitleCommon(details, false), + child: titleAndSubtitleCommon(details), onTap: () { showModalForDescription(details); }, @@ -172,7 +168,7 @@ class _VideoDetailsScreenState extends State { .join(''), shrinkWrap: true, onTapLink: (text, url, title) { - launch(url!); + launchUrl(Uri.parse(url ?? 'https://google.com')); }, ), ), @@ -284,6 +280,7 @@ class _VideoDetailsScreenState extends State { }, user: item.owner, permlink: item.mediaid, + shouldResize: false, ); } diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index 3fb61f23..73c844c5 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -8,17 +8,18 @@ import 'package:http/http.dart' as http; import 'custom_circle_avatar.dart'; class ListTileVideo extends StatelessWidget { - const ListTileVideo({ - Key? key, - required this.placeholder, - required this.url, - required this.userThumbUrl, - required this.title, - required this.subtitle, - required this.onUserTap, - required this.user, - required this.permlink, - }) : super(key: key); + const ListTileVideo( + {Key? key, + required this.placeholder, + required this.url, + required this.userThumbUrl, + required this.title, + required this.subtitle, + required this.onUserTap, + required this.user, + required this.permlink, + required this.shouldResize}) + : super(key: key); final String placeholder; final String url; @@ -28,6 +29,7 @@ class ListTileVideo extends StatelessWidget { final Function onUserTap; final String user; final String permlink; + final bool shouldResize; Widget _errorIndicator() { return Container( @@ -119,7 +121,7 @@ class ListTileVideo extends StatelessWidget { width: MediaQuery.of(context).size.width, child: FadeInImage.assetNetwork( placeholder: placeholder, - image: server.resizedImage(url), + image: shouldResize ? server.resizedImage(url) : url, fit: BoxFit.fitWidth, placeholderErrorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { From cddc0354dcffe129764a4a00566c7bd292101f5c Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 25 Apr 2022 15:40:44 +0530 Subject: [PATCH 059/466] These issues are fixed. 1. name should be clickable too. 3. Video details screen - add author info 4. correct - reward amount - up to 3 fractions 5. Show up-vote, down-vote, hive amount on the video - in hive-search results 6. Show up-vote, down-vote, hive amount on the video - video details page --- .flutter-plugins | 8 +- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 28 ++-- .idea/libraries/Flutter_Plugins.xml | 8 +- .packages | 16 +- .../models/hive_post_info/hive_post_info.dart | 87 +++++++++++ .../video_details_screen.dart | 145 +++++++++++++----- lib/src/widgets/list_tile_video.dart | 98 +++++++----- pubspec.lock | 14 +- pubspec.yaml | 4 +- 10 files changed, 292 insertions(+), 118 deletions(-) create mode 100644 lib/src/models/hive_post_info/hive_post_info.dart diff --git a/.flutter-plugins b/.flutter-plugins index f40b72a9..57e16513 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,9 +1,11 @@ # This is a generated file; do not edit or check into version control. firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/ firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/ -share_plus=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/ -share_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/ -share_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/ +share_plus=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/ +share_plus_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/ +share_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/ +share_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/ +share_plus_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/ url_launcher=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.1.0/ url_launcher_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/ url_launcher_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index debdda70..b278962f 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_macos","share_plus_web"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-04-25 09:33:00.722239","version":"2.10.5"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-04-25 15:37:30.764299","version":"2.10.5"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index c7ffc9f5..d6f05ae2 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -271,7 +271,7 @@ - @@ -460,42 +460,42 @@ - - - - - - @@ -817,7 +817,7 @@ - + @@ -844,12 +844,12 @@ - - - - - - + + + + + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 03197b44..621187ef 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -6,21 +6,23 @@ - - - + + + + + diff --git a/.packages b/.packages index ae461d37..c78009f3 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-04-25 08:13:46.316478. +# Generated by pub on 2022-04-25 14:53:30.160898. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ @@ -42,7 +42,7 @@ flutter_lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlan flutter_markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_markdown-0.6.10/lib/ flutter_test:file:///Applications/flutter/flutter/packages/flutter_test/lib/ flutter_web_plugins:file:///Applications/flutter/flutter/packages/flutter_web_plugins/lib/ -font_awesome_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/font_awesome_flutter-9.2.0/lib/ +font_awesome_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/font_awesome_flutter-10.1.0/lib/ frontend_server_client:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/frontend_server_client-2.1.2/lib/ glob:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/glob-2.0.2/lib/ graphs:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/graphs-2.1.0/lib/ @@ -69,12 +69,12 @@ pool:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/poo provider:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/provider-6.0.2/lib/ pub_semver:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pub_semver-2.1.1/lib/ pubspec_parse:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pubspec_parse-1.2.0/lib/ -share_plus:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-3.1.0/lib/ -share_plus_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-2.0.4/lib/ -share_plus_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-2.1.0/lib/ -share_plus_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_platform_interface-2.1.0/lib/ -share_plus_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-2.0.4/lib/ -share_plus_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-2.0.3/lib/ +share_plus:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/lib/ +share_plus_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/lib/ +share_plus_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/lib/ +share_plus_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_platform_interface-3.0.2/lib/ +share_plus_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/lib/ +share_plus_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/lib/ shelf:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.3.0/lib/ shelf_web_socket:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-1.0.1/lib/ sky_engine:file:///Applications/flutter/flutter/bin/cache/pkg/sky_engine/lib/ diff --git a/lib/src/models/hive_post_info/hive_post_info.dart b/lib/src/models/hive_post_info/hive_post_info.dart new file mode 100644 index 00000000..4e7c9e92 --- /dev/null +++ b/lib/src/models/hive_post_info/hive_post_info.dart @@ -0,0 +1,87 @@ +import 'dart:convert'; + +import 'package:acela/src/utils/safe_convert.dart'; + +class HivePostInfo { + final String jsonrpc; + final HivePostInfoResult result; + final int id; + + HivePostInfo({ + this.jsonrpc = "", + required this.result, + this.id = 0, + }); + + factory HivePostInfo.fromJson(Map? json) => HivePostInfo( + jsonrpc: asString(json, 'jsonrpc'), + result: HivePostInfoResult.fromJson(asMap(json, 'result')), + id: asInt(json, 'id'), + ); + + factory HivePostInfo.fromJsonString(String jsonString) => + HivePostInfo.fromJson(json.decode(jsonString)); +} + +class HivePostInfoResult { + final List resultData; + + HivePostInfoResult({ + required this.resultData, + }); + + factory HivePostInfoResult.fromJson(Map? json) { + var result = json?.keys.map((e) => HivePostInfoPostResultBody.fromJson( + json[e] as Map)) ?? + []; + return HivePostInfoResult(resultData: result.toList()); + } +} + +class HivePostInfoPostResultBody { + final double payout; + final List activeVotes; + final String permlink; + + HivePostInfoPostResultBody({ + required this.payout, + required this.activeVotes, + required this.permlink, + }); + + factory HivePostInfoPostResultBody.fromJson(Map? json) => + HivePostInfoPostResultBody( + payout: asDouble(json, 'payout'), + permlink: asString(json, 'permlink'), + activeVotes: asList(json, 'active_votes') + .map((e) => ActiveVotesItem.fromJson(e)) + .toList(), + ); + + Map toJson() => { + 'payout': payout, + 'permlink': permlink, + 'active_votes': activeVotes.map((e) => e.toJson()), + }; +} + +class ActiveVotesItem { + final int rshares; + final String voter; + + ActiveVotesItem({ + this.rshares = 0, + this.voter = "", + }); + + factory ActiveVotesItem.fromJson(Map? json) => + ActiveVotesItem( + rshares: asInt(json, 'rshares'), + voter: asString(json, 'voter'), + ); + + Map toJson() => { + 'rshares': rshares, + 'voter': voter, + }; +} diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index f2dc96d6..174861b3 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -1,5 +1,8 @@ +import 'dart:convert'; + import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; +import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; @@ -13,6 +16,7 @@ import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/video_player.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:http/http.dart' as http; import 'package:timeago/timeago.dart' as timeago; import 'package:url_launcher/url_launcher.dart'; @@ -28,6 +32,9 @@ class _VideoDetailsScreenState extends State { late Future> recommendedVideos; List recommendations = []; late Future> _loadComments; + double? payout; + int? upVotes; + int? downVotes; @override void initState() { @@ -39,6 +46,7 @@ class _VideoDetailsScreenState extends State { }); _loadComments = widget.vm.loadFirstSetOfComments(widget.vm.author, widget.vm.permlink); + fetchHiveInfo(); } void onUserTap() { @@ -67,29 +75,95 @@ class _VideoDetailsScreenState extends State { ); } + // fetch hive info + void fetchHiveInfo() async { + var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + request.body = json.encode({ + "id": 1, + "jsonrpc": "2.0", + "method": "bridge.get_discussion", + "params": { + "author": widget.vm.author, + "permlink": widget.vm.permlink, + "observer": "" + } + }); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + var result = HivePostInfo.fromJsonString(string) + .result + .resultData + .where((element) => element.permlink == widget.vm.permlink) + .first; + setState(() { + payout = result.payout; + upVotes = result.activeVotes.where((e) => e.rshares > 0).length; + downVotes = result.activeVotes.where((e) => e.rshares < 0).length; + }); + } else { + print(response.reasonPhrase); + } + } + // video description - Widget titleAndSubtitleCommon(VideoDetails details) { + Widget titleAndSubtitle(VideoDetails details) { String string = "📆 ${timeago.format(DateTime.parse(details.created))} · ▶ ${details.views} views · 👥 ${details.community}"; - var downIcon = const Icon(Icons.arrow_drop_down_outlined); - List children = [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(details.title, style: Theme.of(context).textTheme.bodyLarge), - const SizedBox(height: 3), - Text(string, style: Theme.of(context).textTheme.bodySmall), - ], - ), - ), - ]; - children.add(downIcon); + String priceAndVotes = + (payout != null && upVotes != null && downVotes != null) + ? "\$ ${payout!.toStringAsFixed(3)} · 👍 $upVotes · 👎 $downVotes" + : ""; return Container( margin: const EdgeInsets.all(10), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: children, + child: Column( + children: [ + InkWell( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(details.title, + style: Theme.of(context).textTheme.bodyLarge), + const SizedBox(height: 3), + Text(string, + style: Theme.of(context).textTheme.bodySmall), + const SizedBox(height: 3), + Text(priceAndVotes, + style: Theme.of(context).textTheme.bodySmall), + ], + ), + ), + const Icon(Icons.arrow_drop_down_outlined), + ], + ), + onTap: () { + showModalForDescription(details); + }, + ), + SizedBox(height: 10), + InkWell( + child: Row( + children: [ + CustomCircleAvatar( + height: 40, + width: 40, + url: server.userOwnerThumb(details.owner), + ), + SizedBox(width: 10), + Text(details.owner, + style: Theme.of(context).textTheme.bodyLarge), + ], + ), + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (c) => UserChannelScreen(owner: details.owner))); + }, + ) + ], ), ); } @@ -133,16 +207,6 @@ class _VideoDetailsScreenState extends State { ); } - // video description - Widget titleAndSubtitle(VideoDetails details) { - return InkWell( - child: titleAndSubtitleCommon(details), - onTap: () { - showModalForDescription(details); - }, - ); - } - //endregion //region Video Comments @@ -220,23 +284,26 @@ class _VideoDetailsScreenState extends State { return commentsSection(data); } else { return Container( - margin: const EdgeInsets.all(10), - child: Row( - children: const [ - SizedBox( - height: 15, - width: 15, - child: CircularProgressIndicator(value: null)), - SizedBox(width: 10), - Text('Loading comments') - ], - )); + margin: const EdgeInsets.all(10), + child: Row( + children: const [ + SizedBox( + height: 15, + width: 15, + child: CircularProgressIndicator(), + ), + SizedBox(width: 10), + Text('Loading comments') + ], + ), + ); } }, ); } //endregion + // container list view Widget videoWithDetails(VideoDetails details) { return Container( diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index 73c844c5..a9c4aa6d 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -1,13 +1,13 @@ import 'dart:convert'; import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/home_screen_feed_models/hive_payout_response.dart'; +import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'custom_circle_avatar.dart'; -class ListTileVideo extends StatelessWidget { +class ListTileVideo extends StatefulWidget { const ListTileVideo( {Key? key, required this.placeholder, @@ -31,19 +31,34 @@ class ListTileVideo extends StatelessWidget { final String permlink; final bool shouldResize; + @override + State createState() => _ListTileVideoState(); +} + +class _ListTileVideoState extends State { + double? payout; + int? upVotes; + int? downVotes; + + @override + void initState() { + super.initState(); + fetchHiveInfo(); + } + Widget _errorIndicator() { return Container( height: 220, decoration: BoxDecoration( image: DecorationImage( - image: Image.asset(placeholder).image, + image: Image.asset(widget.placeholder).image, fit: BoxFit.fitWidth, ), ), ); } - Widget _amount(double value) { + Widget _amount(String string) { return SizedBox( height: 220, child: Row( @@ -58,7 +73,7 @@ class ListTileVideo extends StatelessWidget { borderRadius: BorderRadiusDirectional.all(Radius.circular(10)), color: Colors.blueGrey), - child: Text('\$ ${value.toStringAsFixed(3)}'), + child: Text(string), ), const SizedBox(height: 5), ], @@ -69,45 +84,43 @@ class ListTileVideo extends StatelessWidget { ); } - Future _futureHivePayout() async { - var request = http.Request('POST', Uri.parse('https://api.deathwing.me/')); + // fetch hive info + void fetchHiveInfo() async { + var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); request.body = json.encode({ - "id": 0, + "id": 1, "jsonrpc": "2.0", - "method": "condenser_api.get_content", - "params": [user, permlink] + "method": "bridge.get_discussion", + "params": { + "author": widget.user, + "permlink": widget.permlink, + "observer": "" + } }); http.StreamedResponse response = await request.send(); if (response.statusCode == 200) { var string = await response.stream.bytesToString(); - return HivePayoutResponse.fromJsonString(string); + var result = HivePostInfo.fromJsonString(string) + .result + .resultData + .where((element) => element.permlink == widget.permlink) + .first; + setState(() { + payout = result.payout; + upVotes = result.activeVotes.where((e) => e.rshares > 0).length; + downVotes = result.activeVotes.where((e) => e.rshares < 0).length; + }); } else { - throw response.reasonPhrase ?? 'Unknown Error'; + print(response.reasonPhrase); } } Widget _hivePayoutLoader() { - return FutureBuilder( - builder: (context, snapshot) { - if (snapshot.hasData) { - var data = snapshot.data as HivePayoutResponse; - if (data.result.pendingPayoutValue == "0.000 HBD") { - var total = double.parse( - data.result.totalPayoutValue.replaceAll(' HBD', '')); - var curator = double.parse( - data.result.curatorPayoutValue.replaceAll(' HBD', '')); - return _amount(total + curator); - } else { - var value = double.parse( - data.result.pendingPayoutValue.replaceAll(' HBD', '')); - return _amount(value); - } - } else { - return Container(); - } - }, - future: _futureHivePayout(), - ); + String priceAndVotes = + (payout != null && upVotes != null && downVotes != null) + ? "\$ ${payout!.toStringAsFixed(3)} · 👍 $upVotes · 👎 $downVotes" + : ""; + return _amount(priceAndVotes); } Widget _thumbnailType(BuildContext context) { @@ -120,8 +133,10 @@ class ListTileVideo extends StatelessWidget { height: 220, width: MediaQuery.of(context).size.width, child: FadeInImage.assetNetwork( - placeholder: placeholder, - image: shouldResize ? server.resizedImage(url) : url, + placeholder: widget.placeholder, + image: widget.shouldResize + ? server.resizedImage(widget.url) + : widget.url, fit: BoxFit.fitWidth, placeholderErrorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { @@ -142,9 +157,9 @@ class ListTileVideo extends StatelessWidget { children: [ InkWell( child: CustomCircleAvatar( - height: 45, width: 45, url: userThumbUrl), + height: 45, width: 45, url: widget.userThumbUrl), onTap: () { - onUserTap(); + widget.onUserTap(); }, ), Container(width: 5), @@ -152,18 +167,19 @@ class ListTileVideo extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title, style: Theme.of(context).textTheme.bodyText1), + Text(widget.title, + style: Theme.of(context).textTheme.bodyText1), Row( children: [ InkWell( - child: Text('👤 $user', + child: Text('👤 ${widget.user}', style: Theme.of(context).textTheme.bodyText2), onTap: () { - onUserTap(); + widget.onUserTap(); }, ), const SizedBox(width: 5), - Text(subtitle, + Text(widget.subtitle, style: Theme.of(context).textTheme.bodyText2), ], ), diff --git a/pubspec.lock b/pubspec.lock index 9eb27167..58f5ac3e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -267,7 +267,7 @@ packages: name: font_awesome_flutter url: "https://pub.dartlang.org" source: hosted - version: "9.2.0" + version: "10.1.0" frontend_server_client: dependency: transitive description: @@ -456,42 +456,42 @@ packages: name: share_plus url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "4.0.4" share_plus_linux: dependency: transitive description: name: share_plus_linux url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "3.0.0" share_plus_macos: dependency: transitive description: name: share_plus_macos url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "3.0.0" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "3.0.2" share_plus_web: dependency: transitive description: name: share_plus_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "3.0.0" share_plus_windows: dependency: transitive description: name: share_plus_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "3.0.0" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1e4cafd9..51c2c6a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,11 +33,11 @@ dependencies: sdk: flutter flutter_dotenv: ^5.0.2 flutter_markdown: ^0.6.9 - font_awesome_flutter: ^9.2.0 + font_awesome_flutter: ^10.1.0 http: ^0.13.4 json_annotation: ^4.4.0 provider: ^6.0.2 - share_plus: ^3.1.0 + share_plus: ^4.0.4 timeago: ^3.1.0 url_launcher: ^6.0.20 video_player: ^2.2.14 From 4943d46ae1803bd60cd75f45861778af20c20c99 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 26 Apr 2022 16:04:28 +0530 Subject: [PATCH 060/466] Bug fixes. --- .flutter-plugins-dependencies | 2 +- .idea/Android-App.iml | 12 ++++ .idea/libraries/Dart_Packages.xml | 8 +++ .packages | 3 +- android/.idea/gradle.xml | 2 +- .../response/communities_response_models.dart | 69 ++++++++++--------- .../communities_screen.dart | 22 +++--- .../community_details_screen.dart | 4 +- .../leaderboard_screen.dart | 22 +++--- .../user_channel_screen.dart | 12 ++-- pubspec.lock | 7 ++ pubspec.yaml | 1 + 12 files changed, 103 insertions(+), 61 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index b278962f..ffe30180 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-04-25 15:37:30.764299","version":"2.10.5"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-04-25 19:35:17.523015","version":"2.10.5"} \ No newline at end of file diff --git a/.idea/Android-App.iml b/.idea/Android-App.iml index 66d15b91..d43ea6cc 100644 --- a/.idea/Android-App.iml +++ b/.idea/Android-App.iml @@ -12,6 +12,18 @@ + + + + + + + + + + + + diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index d6f05ae2..eee52358 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -324,6 +324,13 @@ + + + + + + @@ -825,6 +832,7 @@ + diff --git a/.packages b/.packages index c78009f3..68a80605 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-04-25 14:53:30.160898. +# Generated by pub on 2022-04-25 19:32:20.553999. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ @@ -50,6 +50,7 @@ html:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/htm http:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http-0.13.4/lib/ http_multi_server:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_multi_server-3.2.0/lib/ http_parser:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_parser-4.0.0/lib/ +intl:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/intl-0.17.0/lib/ io:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/io-1.0.3/lib/ js:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3/lib/ json_annotation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_annotation-4.4.0/lib/ diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml index 03ca2859..46e443fd 100644 --- a/android/.idea/gradle.xml +++ b/android/.idea/gradle.xml @@ -10,7 +10,7 @@ + + + + + + @@ -89,7 +96,7 @@ - @@ -152,7 +159,7 @@ - @@ -348,14 +355,14 @@ - - @@ -611,6 +618,13 @@ + + + + + + @@ -621,7 +635,7 @@ - @@ -698,7 +712,7 @@ - @@ -768,14 +782,14 @@ - - @@ -790,6 +804,7 @@ + @@ -801,7 +816,7 @@ - + @@ -810,7 +825,7 @@ - + @@ -835,8 +850,8 @@ - - + + @@ -872,8 +887,9 @@ + - + @@ -884,7 +900,7 @@ - + @@ -894,8 +910,8 @@ - - + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 621187ef..0bcd67e4 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -12,17 +12,17 @@ - - + + diff --git a/.packages b/.packages index 68a80605..54226829 100644 --- a/.packages +++ b/.packages @@ -3,8 +3,9 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-04-25 19:32:20.553999. +# Generated by pub on 2022-04-30 06:51:12.382691. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ +adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ @@ -16,7 +17,7 @@ build_resolvers:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartl build_runner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner-2.1.10/lib/ build_runner_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner_core-7.2.3/lib/ built_collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_collection-5.1.1/lib/ -built_value:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_value-8.2.0/lib/ +built_value:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_value-8.2.3/lib/ characters:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib/ charcode:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib/ checked_yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/checked_yaml-2.0.1/lib/ @@ -25,7 +26,7 @@ clock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cl code_builder:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/code_builder-4.1.0/lib/ collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0/lib/ convert:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/convert-3.0.1/lib/ -crypto:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.1/lib/ +crypto:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.2/lib/ csslib:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.17.1/lib/ cupertino_icons:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.4/lib/ dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.3/lib/ @@ -53,8 +54,8 @@ http_parser:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang. intl:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/intl-0.17.0/lib/ io:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/io-1.0.3/lib/ js:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3/lib/ -json_annotation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_annotation-4.4.0/lib/ -json_serializable:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_serializable-6.1.6/lib/ +json_annotation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_annotation-4.5.0/lib/ +json_serializable:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_serializable-6.2.0/lib/ lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib/ logging:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/logging-1.0.2/lib/ markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/markdown-5.0.0/lib/ @@ -91,8 +92,9 @@ test_api:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org timeago:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timeago-3.2.2/lib/ timing:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timing-1.0.0/lib/ typed_data:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib/ +universal_io:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/universal_io-2.0.4/lib/ url_launcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.1.0/lib/ -url_launcher_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/lib/ +url_launcher_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/lib/ url_launcher_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/lib/ url_launcher_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/lib/ url_launcher_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/lib/ @@ -103,7 +105,7 @@ vector_math:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang. very_good_analysis:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/very_good_analysis-2.4.0/lib/ video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.4.0/lib/ video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/lib/ -video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.2/lib/ +video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/lib/ video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.2/lib/ video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/lib/ video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/lib/ @@ -113,7 +115,7 @@ wakelock_platform_interface:file:///Applications/flutter/flutter/.pub-cache/host wakelock_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/lib/ wakelock_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_windows-0.2.0/lib/ watcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/watcher-1.0.1/lib/ -web_socket_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.1.0/lib/ -win32:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/win32-2.5.1/lib/ +web_socket_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.2.0/lib/ +win32:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/win32-2.5.2/lib/ yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/yaml-3.1.0/lib/ acela:lib/ diff --git a/lib/src/bloc/server.dart b/lib/src/bloc/server.dart index 22967f03..c9a4b24e 100644 --- a/lib/src/bloc/server.dart +++ b/lib/src/bloc/server.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:developer'; class Server { final String domain = "https://3speak.tv"; @@ -33,4 +32,4 @@ class Server { } } -Server server = Server(); \ No newline at end of file +Server server = Server(); diff --git a/lib/src/models/home_screen_feed_models/home_feed.dart b/lib/src/models/home_screen_feed_models/home_feed.dart index c68f3db7..1f37a1ea 100644 --- a/lib/src/models/home_screen_feed_models/home_feed.dart +++ b/lib/src/models/home_screen_feed_models/home_feed.dart @@ -1,4 +1,5 @@ import 'dart:convert'; + import 'package:acela/src/utils/safe_convert.dart'; // final jsonList = json.decode(jsonStr) as List; @@ -6,11 +7,21 @@ import 'package:acela/src/utils/safe_convert.dart'; List homeFeedItemFromString(String string) { final jsonList = json.decode(string) as List; - final list = - jsonList.map((e) => HomeFeedItem.fromJson(e)).toList(); + final list = jsonList.map((e) => HomeFeedItem.fromJson(e)).toList(); return list; } +class PayoutInfo { + double? payout; + int? upVotes; + int? downVotes; + PayoutInfo({ + required this.payout, + required this.upVotes, + required this.downVotes, + }); +} + class HomeFeedItem { final String created; final String language; @@ -26,6 +37,10 @@ class HomeFeedItem { final String ipfs; final HomeFeedItemImage images; + double? payout; + int? upVotes; + int? downVotes; + HomeFeedItem({ this.created = "", this.language = "", @@ -47,36 +62,36 @@ class HomeFeedItem { } factory HomeFeedItem.fromJson(Map? json) => HomeFeedItem( - created: asString(json, 'created'), - language: asString(json, 'language'), - views: asInt(json, 'views'), - author: asString(json, 'author'), - permlink: asString(json, 'permlink'), - title: asString(json, 'title'), - duration: asDouble(json, 'duration'), - isNsfw: asBool(json, 'isNsfw'), - tags: asList(json, 'tags').map((e) => e.toString()).toList(), - isIpfs: asBool(json, 'isIpfs'), - playUrl: asString(json, 'playUrl'), - ipfs: asString(json, 'ipfs'), - images: HomeFeedItemImage.fromJson(asMap(json, 'images')), - ); + created: asString(json, 'created'), + language: asString(json, 'language'), + views: asInt(json, 'views'), + author: asString(json, 'author'), + permlink: asString(json, 'permlink'), + title: asString(json, 'title'), + duration: asDouble(json, 'duration'), + isNsfw: asBool(json, 'isNsfw'), + tags: asList(json, 'tags').map((e) => e.toString()).toList(), + isIpfs: asBool(json, 'isIpfs'), + playUrl: asString(json, 'playUrl'), + ipfs: asString(json, 'ipfs'), + images: HomeFeedItemImage.fromJson(asMap(json, 'images')), + ); Map toJson() => { - 'created': created, - 'language': language, - 'views': views, - 'author': author, - 'permlink': permlink, - 'title': title, - 'duration': duration, - 'isNsfw': isNsfw, - 'tags': tags.map((e) => e), - 'isIpfs': isIpfs, - 'playUrl': playUrl, - 'ipfs': ipfs, - 'images': images.toJson(), - }; + 'created': created, + 'language': language, + 'views': views, + 'author': author, + 'permlink': permlink, + 'title': title, + 'duration': duration, + 'isNsfw': isNsfw, + 'tags': tags.map((e) => e), + 'isIpfs': isIpfs, + 'playUrl': playUrl, + 'ipfs': ipfs, + 'images': images.toJson(), + }; } class HomeFeedItemImage { @@ -88,14 +103,14 @@ class HomeFeedItemImage { this.thumbnail = "", }); - factory HomeFeedItemImage.fromJson(Map? json) => HomeFeedItemImage( - ipfsThumbnail: asString(json, 'ipfs_thumbnail'), - thumbnail: asString(json, 'thumbnail'), - ); + factory HomeFeedItemImage.fromJson(Map? json) => + HomeFeedItemImage( + ipfsThumbnail: asString(json, 'ipfs_thumbnail'), + thumbnail: asString(json, 'thumbnail'), + ); Map toJson() => { - 'ipfs_thumbnail': ipfsThumbnail, - 'thumbnail': thumbnail, - }; + 'ipfs_thumbnail': ipfsThumbnail, + 'thumbnail': thumbnail, + }; } - diff --git a/lib/src/models/search/search_response_models.dart b/lib/src/models/search/search_response_models.dart index 65384e55..9547eb14 100644 --- a/lib/src/models/search/search_response_models.dart +++ b/lib/src/models/search/search_response_models.dart @@ -1,4 +1,5 @@ import 'dart:convert'; + import 'package:acela/src/utils/safe_convert.dart'; class SearchResponseModels { @@ -43,14 +44,16 @@ class SearchResponseResultsItem { final String body; final String bodyMarked; final String imgUrl; - final double payout; - final int totalVotes; - final int upVotes; + double payout; + int totalVotes; + int upVotes; final String createdAt; final List tags; final String app; final int depth; + int? downVotes; + SearchResponseResultsItem( {this.id = 0, this.author = "", diff --git a/lib/src/models/video_recommendation_models/video_recommendation.dart b/lib/src/models/video_recommendation_models/video_recommendation.dart index 93458f2f..13666ed5 100644 --- a/lib/src/models/video_recommendation_models/video_recommendation.dart +++ b/lib/src/models/video_recommendation_models/video_recommendation.dart @@ -1,4 +1,5 @@ import 'dart:convert'; + import 'package:acela/src/utils/safe_convert.dart'; List videoRecommendationItemsFromJson(String str) { @@ -16,6 +17,10 @@ class VideoRecommendationItem { // dobro2020 final String owner; + double? payout; + int? upVotes; + int? downVotes; + VideoRecommendationItem({ this.image = "", this.title = "", @@ -23,18 +28,18 @@ class VideoRecommendationItem { this.owner = "", }); - factory VideoRecommendationItem.fromJson(Map? json) => VideoRecommendationItem( - image: asString(json, 'image'), - title: asString(json, 'title'), - mediaid: asString(json, 'mediaid'), - owner: asString(json, 'owner'), - ); + factory VideoRecommendationItem.fromJson(Map? json) => + VideoRecommendationItem( + image: asString(json, 'image'), + title: asString(json, 'title'), + mediaid: asString(json, 'mediaid'), + owner: asString(json, 'owner'), + ); Map toJson() => { - 'image': image, - 'title': title, - 'mediaid': mediaid, - 'owner': owner, - }; + 'image': image, + 'title': title, + 'mediaid': mediaid, + 'owner': owner, + }; } - diff --git a/lib/src/screens/about/about_home_screen.dart b/lib/src/screens/about/about_home_screen.dart index 14f2f58d..7123af19 100644 --- a/lib/src/screens/about/about_home_screen.dart +++ b/lib/src/screens/about/about_home_screen.dart @@ -38,51 +38,53 @@ class AboutHomeScreen extends StatelessWidget { leading: const FaIcon(FontAwesomeIcons.twitter), title: const Text('Follow us on Twitter'), onTap: () { - launch( - 'https://twitter.com/3speakonline?utm_source=3speak.tv.acela'); + launchUrl(Uri.parse( + 'https://twitter.com/3speakonline?utm_source=3speak.tv.acela')); }, ), ListTile( leading: const FaIcon(FontAwesomeIcons.telegram), title: const Text('Join us on Telegram'), onTap: () { - launch('https://t.me/threespeak?utm_source=3speak.tv.acela'); + launchUrl(Uri.parse( + 'https://t.me/threespeak?utm_source=3speak.tv.acela')); }, ), ListTile( leading: const FaIcon(FontAwesomeIcons.discord), title: const Text('Join us on Discord'), onTap: () { - launch('https://discord.me/3speak?utm_source=3speak.tv.acela'); + launchUrl(Uri.parse( + 'https://discord.me/3speak?utm_source=3speak.tv.acela')); }, ), ListTile( leading: const FaIcon(FontAwesomeIcons.blog), title: const Text('Visit blog - hive.blog/@threespeak'), onTap: () { - launch('https://hive.blog/@threespeak'); + launchUrl(Uri.parse('https://hive.blog/@threespeak')); }, ), ListTile( leading: const Icon(Icons.web), title: const Text('Visit website - spk.network'), onTap: () { - launch('https://spk.network/'); + launchUrl(Uri.parse('https://spk.network/')); }, ), ListTile( leading: const Icon(Icons.web), title: const Text('Visit website - 3speak.tv'), onTap: () { - launch('https://3speak.tv/'); + launchUrl(Uri.parse('https://3speak.tv/')); }, ), ListTile( leading: const Icon(Icons.picture_as_pdf), title: const Text('Terms of service'), onTap: () { - launch( - 'https://threespeakvideo.b-cdn.net/static/terms_of_service.pdf'); + launchUrl(Uri.parse( + 'https://threespeakvideo.b-cdn.net/static/terms_of_service.pdf')); }, ), ListTile( diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index d45a34d9..c98d12eb 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -1,6 +1,10 @@ +import 'dart:async'; +import 'dart:convert'; + import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/communities_models/request/community_details_request.dart'; import 'package:acela/src/models/communities_models/response/community_details_response_models.dart'; +import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; @@ -31,7 +35,7 @@ class CommunityDetailScreen extends StatefulWidget { class _CommunityDetailScreenState extends State with SingleTickerProviderStateMixin { late TabController _tabController; - + Map payout = {}; static const List tabs = [ Tab(text: 'Videos'), Tab(text: 'About'), @@ -96,6 +100,9 @@ class _CommunityDetailScreenState extends State item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; String views = "▶ ${item.views}"; + double? payoutAmount = payout["${item.author}/${item.permlink}"]?.payout; + int? upVotes = payout["${item.author}/${item.permlink}"]?.upVotes; + int? downVotes = payout["${item.author}/${item.permlink}"]?.downVotes; return ListTileVideo( placeholder: 'assets/branding/three_speak_logo.png', url: item.images.thumbnail, @@ -108,9 +115,43 @@ class _CommunityDetailScreenState extends State user: item.author, permlink: item.permlink, shouldResize: true, + downVotes: downVotes, + upVotes: upVotes, + payout: payoutAmount, ); } + void fetchHiveInfo(String user, String permlink) async { + var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + request.body = json.encode({ + "id": 1, + "jsonrpc": "2.0", + "method": "bridge.get_discussion", + "params": {"author": user, "permlink": permlink, "observer": ""} + }); + debugPrint("Loading data for $user/$permlink"); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + var result = HivePostInfo.fromJsonString(string) + .result + .resultData + .where((element) => element.permlink == permlink) + .first; + setState(() { + var upVotes = result.activeVotes.where((e) => e.rshares > 0).length; + var downVotes = result.activeVotes.where((e) => e.rshares < 0).length; + payout["$user/$permlink"] = PayoutInfo( + payout: result.payout, + downVotes: downVotes, + upVotes: upVotes, + ); + }); + } else { + print(response.reasonPhrase); + } + } + Widget _listTile(HomeFeedItem item, BuildContext context, Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { return ListTile( diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 9c39c690..748cb417 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -1,4 +1,8 @@ +import 'dart:async'; +import 'dart:convert'; + import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; @@ -7,8 +11,9 @@ import 'package:acela/src/screens/search/search_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; -import 'package:acela/src/widgets/retry.dart'; import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:http/http.dart' show get; class HomeScreen extends StatefulWidget { const HomeScreen( @@ -60,13 +65,75 @@ class HomeScreen extends StatefulWidget { class _HomeScreenState extends State { final widgets = HomeScreenWidgets(); late HomeScreenViewModel vm; - late Future> _loadingFeed; + List items = []; + var isLoading = false; + Map payout = {}; @override void initState() { super.initState(); vm = HomeScreenViewModel(path: widget.path); - _loadingFeed = vm.loadHomeFeed(); + loadData(); + } + + void loadData() async { + setState(() { + isLoading = true; + }); + var response = await get(Uri.parse(widget.path)); + if (response.statusCode == 200) { + List list = homeFeedItemFromString(response.body); + setState(() { + isLoading = false; + items = list; + var i = 0; + Timer.periodic(const Duration(seconds: 1), (timer) { + fetchHiveInfo(list[i].author, list[i].permlink); + i += 1; + if (i == list.length) { + timer.cancel(); + } + }); + }); + } else { + showError('Status code ${response.statusCode}'); + setState(() { + isLoading = false; + items = []; + }); + } + } + + // fetch hive info + void fetchHiveInfo(String user, String permlink) async { + var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + request.body = json.encode({ + "id": 1, + "jsonrpc": "2.0", + "method": "bridge.get_discussion", + "params": {"author": user, "permlink": permlink, "observer": ""} + }); + debugPrint("Loading data for $user/$permlink"); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + var result = HivePostInfo.fromJsonString(string) + .result + .resultData + .where((element) => element.permlink == permlink) + .first; + setState(() { + var upVotes = result.activeVotes.where((e) => e.rshares > 0).length; + var downVotes = result.activeVotes.where((e) => e.rshares < 0).length; + payout["$user/$permlink"] = PayoutInfo( + payout: result.payout, + downVotes: downVotes, + upVotes: upVotes, + ); + }); + } else { + print(response.reasonPhrase); + } } void onTap(HomeFeedItem item) { @@ -83,22 +150,20 @@ class _HomeScreenState extends State { } } + void showError(String string) { + var snackBar = SnackBar(content: Text('Error: $string')); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + Widget _screen() { - return FutureBuilder( - future: _loadingFeed, - builder: (builder, snapshot) { - if (snapshot.hasError) { - return RetryScreen( - error: snapshot.error?.toString() ?? 'Something went wrong', - onRetry: vm.loadHomeFeed); - } else if (snapshot.hasData) { - List items = snapshot.data! as List; - return widgets.list(items, vm.loadHomeFeed, onTap, onUserTap); - } else { - return widgets.loadingData(); - } - }, - ); + if (isLoading) { + return widgets.loadingData(); + } + return widgets.list(items, (item) { + onTap(item); + }, (item) { + onUserTap(item); + }, payout); } @override diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index eefdb65f..8c7a4b1e 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -11,12 +11,19 @@ class HomeScreenWidgets { return const LoadingScreen(); } - Widget _tileTitle(HomeFeedItem item, BuildContext context, - Function(HomeFeedItem) onUserTap) { + Widget _tileTitle( + HomeFeedItem item, + BuildContext context, + Function(HomeFeedItem) onUserTap, + Map payout, + ) { String timeInString = item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; String views = "▶ ${item.views}"; + double? payoutAmount = payout["${item.author}/${item.permlink}"]?.payout; + int? upVotes = payout["${item.author}/${item.permlink}"]?.upVotes; + int? downVotes = payout["${item.author}/${item.permlink}"]?.downVotes; return ListTileVideo( placeholder: 'assets/branding/three_speak_logo.png', url: item.images.thumbnail, @@ -29,34 +36,43 @@ class HomeScreenWidgets { user: item.author, permlink: item.permlink, shouldResize: true, + downVotes: downVotes, + upVotes: upVotes, + payout: payoutAmount, ); } - Widget _listTile(HomeFeedItem item, BuildContext context, - Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { + Widget _listTile( + HomeFeedItem item, + BuildContext context, + Function(HomeFeedItem) onTap, + Function(HomeFeedItem) onUserTap, + Map payout, + ) { return ListTile( contentPadding: EdgeInsets.zero, minVerticalPadding: 0, - title: _tileTitle(item, context, onUserTap), + title: _tileTitle(item, context, onUserTap, payout), onTap: () { onTap(item); }, ); } - Widget list(List list, Future Function() onRefresh, - Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { - return RefreshIndicator( - onRefresh: onRefresh, - child: ListView.separated( - padding: EdgeInsets.zero, - itemBuilder: (context, index) { - return _listTile(list[index], context, onTap, onUserTap); - }, - separatorBuilder: (context, index) => - const Divider(thickness: 0, height: 15, color: Colors.transparent), - itemCount: list.length, - ), + Widget list( + List list, + Function(HomeFeedItem) onTap, + Function(HomeFeedItem) onUserTap, + Map payout, + ) { + return ListView.separated( + padding: EdgeInsets.zero, + itemBuilder: (context, index) { + return _listTile(list[index], context, onTap, onUserTap, payout); + }, + separatorBuilder: (context, index) => + const Divider(thickness: 0, height: 15, color: Colors.transparent), + itemCount: list.length, ); } } diff --git a/lib/src/screens/search/search_screen.dart b/lib/src/screens/search/search_screen.dart index a81101e8..a0da77b4 100644 --- a/lib/src/screens/search/search_screen.dart +++ b/lib/src/screens/search/search_screen.dart @@ -111,6 +111,9 @@ class _SearchScreenState extends State { user: item.author, permlink: item.permlink, shouldResize: false, + downVotes: item.downVotes, + upVotes: item.downVotes, + payout: item.payout, ), onTap: () { var vm = diff --git a/lib/src/screens/user_channel_screen/user_channel_screen.dart b/lib/src/screens/user_channel_screen/user_channel_screen.dart index 81227a06..8628f67c 100644 --- a/lib/src/screens/user_channel_screen/user_channel_screen.dart +++ b/lib/src/screens/user_channel_screen/user_channel_screen.dart @@ -3,6 +3,7 @@ import 'package:acela/src/screens/user_channel_screen/user_channel_following.dar import 'package:acela/src/screens/user_channel_screen/user_channel_profile.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_videos.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; +import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; class UserChannelScreen extends StatefulWidget { @@ -16,6 +17,8 @@ class UserChannelScreen extends StatefulWidget { class _UserChannelScreenState extends State with SingleTickerProviderStateMixin { late TabController _tabController; + var currentIndex = 0; + var videoKey = GlobalKey(); static const List tabs = [ Tab(text: 'Videos'), @@ -28,6 +31,11 @@ class _UserChannelScreenState extends State void initState() { super.initState(); _tabController = TabController(length: tabs.length, vsync: this); + _tabController.addListener(() { + setState(() { + currentIndex = _tabController.index; + }); + }); } @override @@ -36,6 +44,38 @@ class _UserChannelScreenState extends State _tabController.dispose(); } + Widget _sortButton() { + return IconButton( + onPressed: () { + _showBottomSheet(); + }, + icon: const Icon(Icons.sort), + ); + } + + void _showBottomSheet() { + showAdaptiveActionSheet( + context: context, + title: const Text('Sort by:'), + androidBorderRadius: 30, + actions: [ + BottomSheetAction( + title: const Text('Newest'), + onPressed: () { + videoKey.currentState?.sortByNewest(); + }, + ), + BottomSheetAction( + title: const Text('Most Viewed'), + onPressed: () { + videoKey.currentState?.sortByMostViewed(); + }, + ), + ], + cancelAction: CancelAction(title: const Text('Cancel')), + ); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -53,6 +93,7 @@ class _UserChannelScreenState extends State Text(widget.owner) ], ), + actions: currentIndex == 0 ? [_sortButton()] : [], bottom: TabBar( controller: _tabController, tabs: tabs, @@ -62,7 +103,7 @@ class _UserChannelScreenState extends State body: TabBarView( controller: _tabController, children: [ - UserChannelVideos(owner: widget.owner), + UserChannelVideos(key: videoKey, owner: widget.owner), UserChannelProfileWidget(owner: widget.owner), UserChannelFollowingWidget(owner: widget.owner, isFollowers: true), UserChannelFollowingWidget(owner: widget.owner, isFollowers: false), diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart index bb81d549..19dcfaa3 100644 --- a/lib/src/screens/user_channel_screen/user_channel_videos.dart +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -1,6 +1,9 @@ +import 'dart:async'; +import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; @@ -9,6 +12,7 @@ import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' show get; +import 'package:http/http.dart' as http; import 'package:timeago/timeago.dart' as timeago; class UserChannelVideos extends StatefulWidget { @@ -16,22 +20,103 @@ class UserChannelVideos extends StatefulWidget { final String owner; @override - State createState() => _UserChannelVideosState(); + State createState() => UserChannelVideosState(); } -class _UserChannelVideosState extends State +class UserChannelVideosState extends State with AutomaticKeepAliveClientMixin { @override bool get wantKeepAlive => true; + var isLoading = false; + List list = []; + Map payout = {}; - Future> loadFeed(String author) async { + @override + void initState() { + super.initState(); + loadFeed(); + } + + void sortByNewest() { + setState(() { + list.sort((a, b) { + return (a.createdAt ?? DateTime.now()) + .compareTo(b.createdAt ?? DateTime.now()); + }); + list = list.reversed.toList(); + }); + } + + void sortByMostViewed() { + setState(() { + list.sort((a, b) { + return a.views > b.views + ? -1 + : a.views < b.views + ? 1 + : 0; + }); + }); + } + + void loadFeed() async { + setState(() { + isLoading = true; + }); var response = await get(Uri.parse("${server.domain}/apiv2/feeds/@${widget.owner}")); if (response.statusCode == 200) { List list = homeFeedItemFromString(response.body); - return list; + setState(() { + this.list = list; + isLoading = false; + }); + var i = 0; + Timer.periodic(const Duration(seconds: 1), (timer) { + fetchHiveInfo(list[i].author, list[i].permlink); + i += 1; + if (i == list.length) { + timer.cancel(); + } + }); + } else { + showError("Status code is ${response.statusCode}"); + setState(() { + this.list = []; + isLoading = false; + }); + } + } + + // fetch hive info + void fetchHiveInfo(String user, String permlink) async { + var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + request.body = json.encode({ + "id": 1, + "jsonrpc": "2.0", + "method": "bridge.get_discussion", + "params": {"author": user, "permlink": permlink, "observer": ""} + }); + debugPrint("Loading data for $user/$permlink"); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + var result = HivePostInfo.fromJsonString(string) + .result + .resultData + .where((element) => element.permlink == permlink) + .first; + setState(() { + var upVotes = result.activeVotes.where((e) => e.rshares > 0).length; + var downVotes = result.activeVotes.where((e) => e.rshares < 0).length; + payout["$user/$permlink"] = PayoutInfo( + payout: result.payout, + downVotes: downVotes, + upVotes: upVotes, + ); + }); } else { - throw "Status code is ${response.statusCode}"; + print(response.reasonPhrase); } } @@ -41,6 +126,9 @@ class _UserChannelVideosState extends State item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; String views = "▶ ${item.views}"; + double? payoutAmount = payout["${item.author}/${item.permlink}"]?.payout; + int? upVotes = payout["${item.author}/${item.permlink}"]?.upVotes; + int? downVotes = payout["${item.author}/${item.permlink}"]?.downVotes; return ListTileVideo( placeholder: 'assets/branding/three_speak_logo.png', url: item.images.thumbnail, @@ -53,6 +141,9 @@ class _UserChannelVideosState extends State user: item.author, permlink: item.permlink, shouldResize: true, + downVotes: downVotes, + upVotes: upVotes, + payout: payoutAmount, ); } @@ -68,38 +159,38 @@ class _UserChannelVideosState extends State ); } + void showError(String string) { + var snackBar = SnackBar(content: Text('Error: $string')); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + Widget _futureVideos() { - return FutureBuilder( - future: loadFeed(widget.owner), - builder: (context, snapshot) { - if (snapshot.hasError) { - return const Text('Error loading user profile'); - } else if (snapshot.hasData) { - var data = snapshot.data! as List; - return ListView.separated( - itemBuilder: (context, index) { - return _listTile(data[index], context, (item) { - var viewModel = VideoDetailsViewModel( - author: item.author, permlink: item.permlink); - Navigator.of(context).push(MaterialPageRoute( - builder: (context) => VideoDetailsScreen(vm: viewModel))); - }, (owner) { - log("tapped on user ${owner.author}"); - }); - }, - separatorBuilder: (context, index) => const Divider( - thickness: 0, height: 15, color: Colors.transparent), - itemCount: data.length, - ); - } else { - return const LoadingScreen(); - } + if (isLoading) { + return const LoadingScreen(); + } + if (list.isEmpty) { + return Center(child: const Text('No videos found.')); + } + return ListView.separated( + itemBuilder: (context, index) { + return _listTile(list[index], context, (item) { + var viewModel = VideoDetailsViewModel( + author: item.author, permlink: item.permlink); + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => VideoDetailsScreen(vm: viewModel))); + }, (owner) { + log("tapped on user ${owner.author}"); + }); }, + separatorBuilder: (context, index) => + const Divider(thickness: 0, height: 15, color: Colors.transparent), + itemCount: list.length, ); } @override Widget build(BuildContext context) { + super.build(context); return _futureVideos(); } } diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 174861b3..df3dbf6a 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -348,6 +348,9 @@ class _VideoDetailsScreenState extends State { user: item.owner, permlink: item.mediaid, shouldResize: false, + downVotes: item.downVotes, + upVotes: item.downVotes, + payout: item.payout, ); } diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index a9c4aa6d..71fe0017 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -1,25 +1,24 @@ -import 'dart:convert'; - import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; import 'custom_circle_avatar.dart'; class ListTileVideo extends StatefulWidget { - const ListTileVideo( - {Key? key, - required this.placeholder, - required this.url, - required this.userThumbUrl, - required this.title, - required this.subtitle, - required this.onUserTap, - required this.user, - required this.permlink, - required this.shouldResize}) - : super(key: key); + const ListTileVideo({ + Key? key, + required this.placeholder, + required this.url, + required this.userThumbUrl, + required this.title, + required this.subtitle, + required this.onUserTap, + required this.user, + required this.permlink, + required this.shouldResize, + required this.payout, + required this.upVotes, + required this.downVotes, + }) : super(key: key); final String placeholder; final String url; @@ -30,21 +29,34 @@ class ListTileVideo extends StatefulWidget { final String user; final String permlink; final bool shouldResize; + final double? payout; + final int? upVotes; + final int? downVotes; @override State createState() => _ListTileVideoState(); } class _ListTileVideoState extends State { - double? payout; - int? upVotes; - int? downVotes; - - @override - void initState() { - super.initState(); - fetchHiveInfo(); - } + // double? payout; + // int? upVotes; + // int? downVotes; + // + // @override + // void initState() { + // super.initState(); + // if (widget.payout == null && + // widget.upVotes == null && + // widget.downVotes == null) { + // fetchHiveInfo(); + // } else { + // setState(() { + // payout = widget.payout; + // upVotes = widget.upVotes; + // downVotes = widget.downVotes; + // }); + // } + // } Widget _errorIndicator() { return Container( @@ -85,41 +97,45 @@ class _ListTileVideoState extends State { } // fetch hive info - void fetchHiveInfo() async { - var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); - request.body = json.encode({ - "id": 1, - "jsonrpc": "2.0", - "method": "bridge.get_discussion", - "params": { - "author": widget.user, - "permlink": widget.permlink, - "observer": "" - } - }); - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - var string = await response.stream.bytesToString(); - var result = HivePostInfo.fromJsonString(string) - .result - .resultData - .where((element) => element.permlink == widget.permlink) - .first; - setState(() { - payout = result.payout; - upVotes = result.activeVotes.where((e) => e.rshares > 0).length; - downVotes = result.activeVotes.where((e) => e.rshares < 0).length; - }); - } else { - print(response.reasonPhrase); - } - } + // void fetchHiveInfo() async { + // var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + // request.body = json.encode({ + // "id": 1, + // "jsonrpc": "2.0", + // "method": "bridge.get_discussion", + // "params": { + // "author": widget.user, + // "permlink": widget.permlink, + // "observer": "" + // } + // }); + // http.StreamedResponse response = await request.send(); + // if (response.statusCode == 200) { + // var string = await response.stream.bytesToString(); + // var result = HivePostInfo.fromJsonString(string) + // .result + // .resultData + // .where((element) => element.permlink == widget.permlink) + // .first; + // setState(() { + // payout = result.payout; + // var upVotes = result.activeVotes.where((e) => e.rshares > 0).length; + // var downVotes = result.activeVotes.where((e) => e.rshares < 0).length; + // this.upVotes = upVotes; + // this.downVotes = downVotes; + // widget.hiveInfo(result.payout, upVotes, downVotes); + // }); + // } else { + // print(response.reasonPhrase); + // } + // } Widget _hivePayoutLoader() { - String priceAndVotes = - (payout != null && upVotes != null && downVotes != null) - ? "\$ ${payout!.toStringAsFixed(3)} · 👍 $upVotes · 👎 $downVotes" - : ""; + String priceAndVotes = (widget.payout != null && + widget.upVotes != null && + widget.downVotes != null) + ? "\$ ${widget.payout!.toStringAsFixed(3)} · 👍 ${widget.upVotes} · 👎 ${widget.downVotes}" + : ""; return _amount(priceAndVotes); } @@ -162,33 +178,30 @@ class _ListTileVideoState extends State { widget.onUserTap(); }, ), - Container(width: 5), + SizedBox(width: 5), Flexible( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(widget.title, style: Theme.of(context).textTheme.bodyText1), - Row( - children: [ - InkWell( - child: Text('👤 ${widget.user}', - style: Theme.of(context).textTheme.bodyText2), - onTap: () { - widget.onUserTap(); - }, - ), - const SizedBox(width: 5), - Text(widget.subtitle, - style: Theme.of(context).textTheme.bodyText2), - ], + SizedBox(height: 5), + InkWell( + child: Text('👤 ${widget.user}', + style: Theme.of(context).textTheme.bodyText2), + onTap: () { + widget.onUserTap(); + }, ), ], ), ) ], ), - ) + ), + Center( + child: Text(widget.subtitle, + style: Theme.of(context).textTheme.bodyText2)), ], ); } diff --git a/pubspec.lock b/pubspec.lock index 3fd2bcdf..3b5b2ab7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -8,6 +8,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "39.0.0" + adaptive_action_sheet: + dependency: "direct main" + description: + name: adaptive_action_sheet + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" analyzer: dependency: transitive description: @@ -91,7 +98,7 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.2.0" + version: "8.2.3" characters: dependency: transitive description: @@ -154,7 +161,7 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" csslib: dependency: transitive description: @@ -344,14 +351,14 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "4.5.0" json_serializable: dependency: "direct dev" description: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "6.1.6" + version: "6.2.0" lints: dependency: transitive description: @@ -602,6 +609,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + universal_io: + dependency: transitive + description: + name: universal_io + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" url_launcher: dependency: "direct main" description: @@ -615,7 +629,7 @@ packages: name: url_launcher_android url: "https://pub.dartlang.org" source: hosted - version: "6.0.15" + version: "6.0.16" url_launcher_ios: dependency: transitive description: @@ -692,7 +706,7 @@ packages: name: video_player_avfoundation url: "https://pub.dartlang.org" source: hosted - version: "2.3.2" + version: "2.3.3" video_player_platform_interface: dependency: transitive description: @@ -762,14 +776,14 @@ packages: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.5.1" + version: "2.5.2" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 4e121e79..469e8b9f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,6 +27,7 @@ environment: # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: + adaptive_action_sheet: ^2.0.1 chewie: ^1.3.0 firebase_core: ^1.12.0 flutter: From c4488741f61513e9338526bc7600bb69a6f2ea8f Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 1 May 2022 09:35:23 +0530 Subject: [PATCH 062/466] login integration work in progress. --- .DS_Store | Bin 6148 -> 6148 bytes .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 40 +++++++++ .packages | 7 +- ios/.DS_Store | Bin 6148 -> 6148 bytes ios/Podfile.lock | 24 ++--- ios/Runner.xcodeproj/project.pbxproj | 20 +++++ ios/Runner/AcelaWebViewController.swift | 73 +++++++++++++++ ios/Runner/AppDelegate.swift | 22 +++-- ios/Runner/Base.lproj/Main.storyboard | 37 ++++++-- ios/Runner/Bridges/AuthBridge.swift | 49 ++++++++++ ios/Runner/public/index.html | 44 +++++++++ .../home_screen_feed_models/home_feed.dart | 4 - lib/src/models/login/login_response.dart | 84 ++++++++++++++++++ .../models/search/search_response_models.dart | 8 +- .../video_recommendation.dart | 4 - .../community_details_screen.dart | 1 - .../screens/drawer_screen/drawer_screen.dart | 15 ++++ lib/src/screens/home_screen/home_screen.dart | 4 - .../home_screen/home_screen_view_model.dart | 17 ---- lib/src/screens/login/login_screen.dart | 66 ++++++++++++++ lib/src/screens/search/search_screen.dart | 51 ++++++++++- .../user_channel_videos.dart | 1 - .../video_details_screen.dart | 67 ++++++++++++-- lib/src/widgets/list_tile_video.dart | 54 ----------- pubspec.lock | 37 +++++++- pubspec.yaml | 5 ++ 27 files changed, 607 insertions(+), 129 deletions(-) create mode 100644 ios/Runner/AcelaWebViewController.swift create mode 100644 ios/Runner/Bridges/AuthBridge.swift create mode 100644 ios/Runner/public/index.html create mode 100644 lib/src/models/login/login_response.dart delete mode 100644 lib/src/screens/home_screen/home_screen_view_model.dart create mode 100644 lib/src/screens/login/login_screen.dart diff --git a/.DS_Store b/.DS_Store index aa38b5f10ddb820cfa227fe34955814c679270da..4f30f963d192ba728c5e4a2764e937e761516057 100644 GIT binary patch delta 233 zcmZoMXfc=|#>B)qu~2NHo}wrl0|Nsi1A_nqLlHwFLjglUPP$?6=8ufa8S6n(91NKZ zc|e$oES;R6TL6@U0Sq;{`7SO=Ir&LI1sq$&=6{moKjH{tqnnkRpMpo76vEPi48ve# mOE>c{CbMp4=iui6dIad$@640=MJzdh{s1BdhRp#YTbKbN$TFb- delta 85 zcmZoMXfc=|#>B`mu~2NHo}wrd0|Nsi1A_oVaY0f}eiD$kBdK6w;qu7_A}pJiGbONY lUcfwqaWgvyKL=3L=84STnJ4p$SaJXrg7h(M4iMSG3;>5t6lVYc diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index e4bdbb56..ec8e6066 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-04-30 14:48:22.538891","version":"2.10.5"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-05-01 09:30:15.778030","version":"2.10.5"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 612e42d4..4563ba56 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -37,6 +37,13 @@ + + + + + + @@ -44,6 +51,20 @@ + + + + + + + + + + + + @@ -184,6 +205,13 @@ + + + + + + @@ -303,6 +331,13 @@ + + + + + + @@ -808,7 +843,10 @@ + + + @@ -829,6 +867,7 @@ + @@ -843,6 +882,7 @@ + diff --git a/.packages b/.packages index 54226829..731e6617 100644 --- a/.packages +++ b/.packages @@ -3,13 +3,16 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-04-30 06:51:12.382691. +# Generated by pub on 2022-05-01 07:51:09.046162. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ +base_x:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/base_x-2.0.0/lib/ boolean_selector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/ +bs58:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/bs58-1.0.2/lib/ +bs58check:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/bs58check-1.0.2/lib/ build:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build-2.3.0/lib/ build_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_config-1.0.0/lib/ build_daemon:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_daemon-3.1.0/lib/ @@ -30,6 +33,7 @@ crypto:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/c csslib:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.17.1/lib/ cupertino_icons:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.4/lib/ dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.3/lib/ +elliptic:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/elliptic-0.3.8/lib/ fake_async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0/lib/ ffi:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.1.2/lib/ file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib/ @@ -47,6 +51,7 @@ font_awesome_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub. frontend_server_client:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/frontend_server_client-2.1.2/lib/ glob:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/glob-2.0.2/lib/ graphs:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/graphs-2.1.0/lib/ +hex:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/hex-0.2.0/lib/ html:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/html-0.15.0/lib/ http:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http-0.13.4/lib/ http_multi_server:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_multi_server-3.2.0/lib/ diff --git a/ios/.DS_Store b/ios/.DS_Store index cc25182145e410f6af4ae876ead76e04f664e2d4..7404f1567f2e8f2f3682f40eb0df8b94f30ee5dd 100644 GIT binary patch delta 338 zcmZoMXfc=|#>B!ku~2NHo}wrh0|Nsi1A_nqLn=d2Qh9MfQcix-=8MeBnd?DPYz#pR zr3`sMh$IaZ-uu5=%;pof3AvvYFu^1Feq0|G{%r@(+0O2eog zAOpo$Wx+*xIr(|%Kyi>B0ho^``!GptHehB)qu~2NHo}wrR0|Nsi1A_nqLn=cNgC0W#Lo!4D#=_-{j2x2 8.0) - GoogleUtilities/Environment (~> 7.7) - GoogleUtilities/Logger (~> 7.7) - - FirebaseCoreDiagnostics (8.11.0): + - FirebaseCoreDiagnostics (8.15.0): - GoogleDataTransport (~> 9.1) - GoogleUtilities/Environment (~> 7.7) - GoogleUtilities/Logger (~> 7.7) @@ -27,7 +27,7 @@ PODS: - nanopb/encode (= 2.30908.0) - nanopb/decode (2.30908.0) - nanopb/encode (2.30908.0) - - PromisesObjC (2.0.0) + - PromisesObjC (2.1.0) - share_plus (0.0.1): - Flutter - url_launcher_ios (0.0.1): @@ -70,15 +70,15 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/wakelock/ios" SPEC CHECKSUMS: - Firebase: 44dd9724c84df18b486639e874f31436eaa9a20c - firebase_core: 08f6a85f62060111de5e98d6a214810d11365de9 - FirebaseCore: 2f4f85b453cc8fea4bb2b37e370007d2bcafe3f0 - FirebaseCoreDiagnostics: 64d9709d804a6c25bd77841371c1fcfd909d5601 + Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d + firebase_core: fa19947d8db1c0a62d8872c45039b3113829cd2e + FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1 + FirebaseCoreDiagnostics: 92e07a649aeb66352b319d43bdd2ee3942af84cb Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 - PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 + PromisesObjC: 99b6f43f9e1044bd87a95a60beff28c2c44ddb72 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 314dd9f4..d9ac5f50 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -8,6 +8,9 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 1B6A5097281E206800480755 /* AcelaWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6A5096281E206800480755 /* AcelaWebViewController.swift */; }; + 1B6A509E281E219E00480755 /* public in Resources */ = {isa = PBXBuildFile; fileRef = 1B6A509D281E219E00480755 /* public */; }; + 1B6A50A1281E290300480755 /* AuthBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6A50A0281E290300480755 /* AuthBridge.swift */; }; 1BBABA1B27E2F977000ABB58 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1BBABA1A27E2F977000ABB58 /* GoogleService-Info.plist */; }; 23F3017383FF2D45A9FFE1B2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 900CC1210BBABA2901A394FB /* Pods_Runner.framework */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; @@ -33,6 +36,9 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 1B6A5096281E206800480755 /* AcelaWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AcelaWebViewController.swift; sourceTree = ""; }; + 1B6A509D281E219E00480755 /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; }; + 1B6A50A0281E290300480755 /* AuthBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthBridge.swift; sourceTree = ""; }; 1BBABA1A27E2F977000ABB58 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 3655DA9EF6F21F87FCBD0D8C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; @@ -63,6 +69,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1B6A509F281E28F600480755 /* Bridges */ = { + isa = PBXGroup; + children = ( + 1B6A50A0281E290300480755 /* AuthBridge.swift */, + ); + path = Bridges; + sourceTree = ""; + }; 2BD77FF19862F46541915B75 /* Pods */ = { isa = PBXGroup; children = ( @@ -121,8 +135,11 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 1B6A509F281E28F600480755 /* Bridges */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 1BBABA1A27E2F977000ABB58 /* GoogleService-Info.plist */, + 1B6A5096281E206800480755 /* AcelaWebViewController.swift */, + 1B6A509D281E219E00480755 /* public */, ); path = Runner; sourceTree = ""; @@ -193,6 +210,7 @@ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 1BBABA1B27E2F977000ABB58 /* GoogleService-Info.plist in Resources */, + 1B6A509E281E219E00480755 /* public in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -276,6 +294,8 @@ buildActionMask = 2147483647; files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1B6A5097281E206800480755 /* AcelaWebViewController.swift in Sources */, + 1B6A50A1281E290300480755 /* AuthBridge.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift new file mode 100644 index 00000000..372f5e75 --- /dev/null +++ b/ios/Runner/AcelaWebViewController.swift @@ -0,0 +1,73 @@ +// +// AcelaWebViewController.swift +// Runner +// +// Created by Sagar on 01/05/22. +// + +import UIKit +import WebKit + +class AcelaWebViewController: UIViewController { + let acela = "acela" + let config = WKWebViewConfiguration() + let rect = CGRect(x: 0, y: 0, width: 10, height: 10) + var webView: WKWebView? + var didFinish = false + var postingKeyValidationHandler: ((Bool) -> Void)? + + override func viewDidLoad() { + super.viewDidLoad() + config.userContentController.add(self, name: acela) + webView = WKWebView(frame: rect, configuration: config) + webView?.navigationDelegate = self + guard + let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "public") + else { return } + let dir = url.deletingLastPathComponent() + webView?.loadFileURL(url, allowingReadAccessTo: dir) + } + + func validatePostingKey( + username: String, + postingKey: String, + handler: @escaping (Bool) -> Void + ) { + postingKeyValidationHandler = handler + OperationQueue.main.addOperation { + self.webView?.evaluateJavaScript("validateHiveKey('\(username)', '\(postingKey)')") + } + } +} + +extension AcelaWebViewController: WKNavigationDelegate { + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + didFinish = true + } +} + +extension AcelaWebViewController: WKScriptMessageHandler { + func userContentController( + _ userContentController: WKUserContentController, + didReceive message: WKScriptMessage + ) { + guard message.name == acela else { return } + guard let dict = message.body as? [String: AnyObject] else { return } + guard let type = dict["type"] as? String else { return } + switch type { + case "validateHiveKey": + guard + let isValid = dict["valid"] as? Bool, + let accountName = dict["accountName"] as? String, + let postingKey = dict["postingKey"] as? String, + let error = dict["error"] as? String + else { return } + debugPrint("Is it valid? \(isValid ? "TRUE" : "FALSE")") + debugPrint("account name is \(accountName)") + debugPrint("posting key is \(postingKey)") + debugPrint("Error is \(error)") + postingKeyValidationHandler?(isValid) + default: debugPrint("Do nothing here.") + } + } +} diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 70693e4a..8a1e632f 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -3,11 +3,19 @@ import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } + var acela: AcelaWebViewController? + let authBridge = AuthBridge() + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + acela = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "AcelaWebViewController") as? AcelaWebViewController + acela?.viewDidLoad() + + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + authBridge.initiate(controller: controller, window: window, acela: acela) + + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } } diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard index f3c28516..0f0a8a10 100644 --- a/ios/Runner/Base.lproj/Main.storyboard +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -1,8 +1,11 @@ - - + + + - + + + @@ -14,13 +17,37 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Bridges/AuthBridge.swift b/ios/Runner/Bridges/AuthBridge.swift new file mode 100644 index 00000000..e7237562 --- /dev/null +++ b/ios/Runner/Bridges/AuthBridge.swift @@ -0,0 +1,49 @@ +// +// AuthBridge.swift +// Runner +// +// Created by Sagar on 01/05/22. +// + +import UIKit +import Flutter + +class AuthBridge { + var window: UIWindow? + var acela: AcelaWebViewController? + + func initiate(controller: FlutterViewController, window: UIWindow?, acela: AcelaWebViewController?) { + self.window = window + self.acela = acela + let authChannel = FlutterMethodChannel( + name: "com.example.acela/auth", + binaryMessenger: controller.binaryMessenger + ) + authChannel.setMethodCallHandler({ + [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + // Note: this method is invoked on the UI thread. + guard + call.method == "validate", + let arguments = call.arguments as? NSDictionary, + let username = arguments ["username"] as? String, + let password = arguments["postingKey"] as? String + else { + result(FlutterMethodNotImplemented) + return + } + self?.authenticate(username: username, postingKey: password, result: result) + }) + } + + private func authenticate(username: String, postingKey: String, result: @escaping FlutterResult) { + guard let acela = acela else { + result(FlutterError(code: "ERROR", + message: "Error setting up Hive", + details: nil)) + return + } + acela.validatePostingKey(username: username, postingKey: postingKey) { isValid in + result(isValid ? "true" : "false") + } + } +} diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html new file mode 100644 index 00000000..85087d0d --- /dev/null +++ b/ios/Runner/public/index.html @@ -0,0 +1,44 @@ + + + + + + + + 3Speak Acela + + + + + + + + diff --git a/lib/src/models/home_screen_feed_models/home_feed.dart b/lib/src/models/home_screen_feed_models/home_feed.dart index 1f37a1ea..382c0ff3 100644 --- a/lib/src/models/home_screen_feed_models/home_feed.dart +++ b/lib/src/models/home_screen_feed_models/home_feed.dart @@ -37,10 +37,6 @@ class HomeFeedItem { final String ipfs; final HomeFeedItemImage images; - double? payout; - int? upVotes; - int? downVotes; - HomeFeedItem({ this.created = "", this.language = "", diff --git a/lib/src/models/login/login_response.dart b/lib/src/models/login/login_response.dart new file mode 100644 index 00000000..938d4867 --- /dev/null +++ b/lib/src/models/login/login_response.dart @@ -0,0 +1,84 @@ +import 'dart:convert'; + +import 'package:acela/src/utils/safe_convert.dart'; + +class LoginResponse { + final String jsonrpc; + final List result; + final int id; + + LoginResponse({ + this.jsonrpc = "", + required this.result, + this.id = 0, + }); + + factory LoginResponse.fromJson(Map? json) => LoginResponse( + jsonrpc: asString(json, 'jsonrpc'), + result: asList(json, 'result') + .map((e) => LoginResponseResult.fromJson(e)) + .toList(), + id: asInt(json, 'id'), + ); + + factory LoginResponse.fromJsonString(String jsonString) => + LoginResponse.fromJson(json.decode(jsonString)); + + Map toJson() => { + 'jsonrpc': jsonrpc, + 'result': result.map((e) => e.toJson()), + 'id': id, + }; +} + +class LoginResponseResult { + final int id; + final String name; + final LoginResponseResultKeyAuths owner; + final LoginResponseResultKeyAuths active; + final LoginResponseResultKeyAuths posting; + + LoginResponseResult({ + this.id = 0, + this.name = "", + required this.owner, + required this.active, + required this.posting, + }); + + factory LoginResponseResult.fromJson(Map? json) => + LoginResponseResult( + id: asInt(json, 'id'), + name: asString(json, 'name'), + owner: LoginResponseResultKeyAuths.fromJson(asMap(json, 'owner')), + active: LoginResponseResultKeyAuths.fromJson(asMap(json, 'active')), + posting: LoginResponseResultKeyAuths.fromJson(asMap(json, 'posting')), + ); + + Map toJson() => { + 'id': id, + 'name': name, + 'owner': owner.toJson(), + 'active': active.toJson(), + 'posting': posting.toJson(), + }; +} + +class LoginResponseResultKeyAuths { + final List keyAuths; + + LoginResponseResultKeyAuths({ + required this.keyAuths, + }); + + factory LoginResponseResultKeyAuths.fromJson(Map? json) => + LoginResponseResultKeyAuths( + keyAuths: asList(json, 'key_auths') + .map((e) => (e as List).first as String) + .toList(), + ); + + Map toJson() => { + 'key_auths': keyAuths.map((e) => e), + }; +} diff --git a/lib/src/models/search/search_response_models.dart b/lib/src/models/search/search_response_models.dart index 9547eb14..3c706d07 100644 --- a/lib/src/models/search/search_response_models.dart +++ b/lib/src/models/search/search_response_models.dart @@ -44,16 +44,14 @@ class SearchResponseResultsItem { final String body; final String bodyMarked; final String imgUrl; - double payout; - int totalVotes; - int upVotes; + final double payout; + final int totalVotes; + final int upVotes; final String createdAt; final List tags; final String app; final int depth; - int? downVotes; - SearchResponseResultsItem( {this.id = 0, this.author = "", diff --git a/lib/src/models/video_recommendation_models/video_recommendation.dart b/lib/src/models/video_recommendation_models/video_recommendation.dart index 13666ed5..824f107a 100644 --- a/lib/src/models/video_recommendation_models/video_recommendation.dart +++ b/lib/src/models/video_recommendation_models/video_recommendation.dart @@ -17,10 +17,6 @@ class VideoRecommendationItem { // dobro2020 final String owner; - double? payout; - int? upVotes; - int? downVotes; - VideoRecommendationItem({ this.image = "", this.title = "", diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index c98d12eb..946a287b 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -129,7 +129,6 @@ class _CommunityDetailScreenState extends State "method": "bridge.get_discussion", "params": {"author": user, "permlink": permlink, "observer": ""} }); - debugPrint("Loading data for $user/$permlink"); http.StreamedResponse response = await request.send(); if (response.statusCode == 200) { var string = await response.stream.bytesToString(); diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 108afad6..1ca5e837 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -3,6 +3,7 @@ import 'package:acela/src/screens/about/about_home_screen.dart'; import 'package:acela/src/screens/communities_screen/communities_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; +import 'package:acela/src/screens/login/login_screen.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -128,6 +129,18 @@ class DrawerScreen extends StatelessWidget { ); } + Widget _login(BuildContext context) { + return ListTile( + leading: const Icon(Icons.login), + title: const Text("Log in"), + onTap: () { + Navigator.pop(context); + Navigator.of(context) + .push(MaterialPageRoute(builder: (c) => const LoginScreen())); + }, + ); + } + Widget _divider() { return const Divider( height: 1, @@ -153,6 +166,8 @@ class DrawerScreen extends StatelessWidget { _divider(), _changeTheme(context), _divider(), + _login(context), + _divider(), ], ); } diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 748cb417..a2ee22f6 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -5,7 +5,6 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; -import 'package:acela/src/screens/home_screen/home_screen_view_model.dart'; import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; import 'package:acela/src/screens/search/search_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; @@ -64,7 +63,6 @@ class HomeScreen extends StatefulWidget { class _HomeScreenState extends State { final widgets = HomeScreenWidgets(); - late HomeScreenViewModel vm; List items = []; var isLoading = false; Map payout = {}; @@ -72,7 +70,6 @@ class _HomeScreenState extends State { @override void initState() { super.initState(); - vm = HomeScreenViewModel(path: widget.path); loadData(); } @@ -113,7 +110,6 @@ class _HomeScreenState extends State { "method": "bridge.get_discussion", "params": {"author": user, "permlink": permlink, "observer": ""} }); - debugPrint("Loading data for $user/$permlink"); http.StreamedResponse response = await request.send(); if (response.statusCode == 200) { var string = await response.stream.bytesToString(); diff --git a/lib/src/screens/home_screen/home_screen_view_model.dart b/lib/src/screens/home_screen/home_screen_view_model.dart deleted file mode 100644 index ceeb4666..00000000 --- a/lib/src/screens/home_screen/home_screen_view_model.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; -import 'package:http/http.dart' show get; - -class HomeScreenViewModel { - HomeScreenViewModel({required this.path}); - final String path; - - Future> loadHomeFeed() async { - var response = await get(Uri.parse(path)); - if (response.statusCode == 200) { - List list = homeFeedItemFromString(response.body); - return list; - } else { - throw 'Status code ${response.statusCode}'; - } - } -} \ No newline at end of file diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart new file mode 100644 index 00000000..c5007fdf --- /dev/null +++ b/lib/src/screens/login/login_screen.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class LoginScreen extends StatefulWidget { + const LoginScreen({Key? key}) : super(key: key); + + @override + State createState() => _LoginScreenState(); +} + +class _LoginScreenState extends State { + var isLoading = false; + static const platform = MethodChannel('com.example.acela/auth'); + var isValid = 'not validated yet'; + + void onLoginTapped() async { + setState(() { + isLoading = true; + }); + try { + final String result = await platform.invokeMethod( + 'validate', + { + 'username': 'sagarkothari88', + 'postingKey': '', + }, + ); + setState(() { + isLoading = false; + isValid = result; + }); + } catch (e) { + setState(() { + isLoading = false; + isValid = 'failed'; + }); + } + } + + void showError(String string) { + var snackBar = SnackBar(content: Text('Error: $string')); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Login'), + ), + body: isLoading + ? const Center(child: CircularProgressIndicator()) + : Column( + children: [ + Text('is valid key - $isValid'), + ], + ), + floatingActionButton: isLoading + ? null + : FloatingActionButton( + onPressed: onLoginTapped, + child: Icon(Icons.login), + ), + ); + } +} diff --git a/lib/src/screens/search/search_screen.dart b/lib/src/screens/search/search_screen.dart index a0da77b4..da4dbdb7 100644 --- a/lib/src/screens/search/search_screen.dart +++ b/lib/src/screens/search/search_screen.dart @@ -3,6 +3,8 @@ import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/search/search_response_models.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; @@ -26,6 +28,7 @@ class _SearchScreenState extends State { Timer? _timer; List results = []; var loading = false; + Map payout = {}; Future search(String term) async { var headers = { @@ -50,6 +53,14 @@ class _SearchScreenState extends State { setState(() { results = result.results; }); + var i = 0; + Timer.periodic(const Duration(seconds: 1), (timer) { + fetchHiveInfo(results[i].author, results[i].permlink); + i += 1; + if (i == results.length) { + timer.cancel(); + } + }); } else { log(response.reasonPhrase.toString()); setState(() { @@ -58,6 +69,37 @@ class _SearchScreenState extends State { } } + // fetch hive info + void fetchHiveInfo(String user, String permlink) async { + var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + request.body = json.encode({ + "id": 1, + "jsonrpc": "2.0", + "method": "bridge.get_discussion", + "params": {"author": user, "permlink": permlink, "observer": ""} + }); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + var result = HivePostInfo.fromJsonString(string) + .result + .resultData + .where((element) => element.permlink == permlink) + .first; + setState(() { + var upVotes = result.activeVotes.where((e) => e.rshares > 0).length; + var downVotes = result.activeVotes.where((e) => e.rshares < 0).length; + payout["$user/$permlink"] = PayoutInfo( + payout: result.payout, + downVotes: downVotes, + upVotes: upVotes, + ); + }); + } else { + print(response.reasonPhrase); + } + } + @override void initState() { super.initState(); @@ -94,6 +136,9 @@ class _SearchScreenState extends State { var created = DateTime.tryParse(item.createdAt); String timeInString = created != null ? "📆 ${timeago.format(created)}" : ""; + double? payoutAmount = payout["${item.author}/${item.permlink}"]?.payout; + int? upVotes = payout["${item.author}/${item.permlink}"]?.upVotes; + int? downVotes = payout["${item.author}/${item.permlink}"]?.downVotes; return ListTile( contentPadding: EdgeInsets.zero, minVerticalPadding: 0, @@ -111,9 +156,9 @@ class _SearchScreenState extends State { user: item.author, permlink: item.permlink, shouldResize: false, - downVotes: item.downVotes, - upVotes: item.downVotes, - payout: item.payout, + downVotes: downVotes, + upVotes: upVotes, + payout: payoutAmount, ), onTap: () { var vm = diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart index 19dcfaa3..d6490d7a 100644 --- a/lib/src/screens/user_channel_screen/user_channel_videos.dart +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -97,7 +97,6 @@ class UserChannelVideosState extends State "method": "bridge.get_discussion", "params": {"author": user, "permlink": permlink, "observer": ""} }); - debugPrint("Loading data for $user/$permlink"); http.StreamedResponse response = await request.send(); if (response.statusCode == 200) { var string = await response.stream.bytesToString(); diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index df3dbf6a..11f288af 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -1,8 +1,10 @@ +import 'dart:async'; import 'dart:convert'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; @@ -32,6 +34,7 @@ class _VideoDetailsScreenState extends State { late Future> recommendedVideos; List recommendations = []; late Future> _loadComments; + Map payoutData = {}; double? payout; int? upVotes; int? downVotes; @@ -43,10 +46,18 @@ class _VideoDetailsScreenState extends State { setState(() { recommendations = value; }); + var i = 0; + Timer.periodic(const Duration(seconds: 1), (timer) { + fetchHiveInfo(value[i].owner, value[i].mediaid); + i += 1; + if (i == value.length) { + timer.cancel(); + } + }); }); _loadComments = widget.vm.loadFirstSetOfComments(widget.vm.author, widget.vm.permlink); - fetchHiveInfo(); + fetchHiveInfoForThisVideo(); } void onUserTap() { @@ -76,7 +87,7 @@ class _VideoDetailsScreenState extends State { } // fetch hive info - void fetchHiveInfo() async { + void fetchHiveInfoForThisVideo() async { var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); request.body = json.encode({ "id": 1, @@ -106,6 +117,37 @@ class _VideoDetailsScreenState extends State { } } + // fetch hive info + void fetchHiveInfo(String user, String permlink) async { + var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + request.body = json.encode({ + "id": 1, + "jsonrpc": "2.0", + "method": "bridge.get_discussion", + "params": {"author": user, "permlink": permlink, "observer": ""} + }); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + var result = HivePostInfo.fromJsonString(string) + .result + .resultData + .where((element) => element.permlink == permlink) + .first; + setState(() { + var upVotes = result.activeVotes.where((e) => e.rshares > 0).length; + var downVotes = result.activeVotes.where((e) => e.rshares < 0).length; + payoutData["$user/$permlink"] = PayoutInfo( + payout: result.payout, + downVotes: downVotes, + upVotes: upVotes, + ); + }); + } else { + print(response.reasonPhrase); + } + } + // video description Widget titleAndSubtitle(VideoDetails details) { String string = @@ -262,10 +304,14 @@ class _VideoDetailsScreenState extends State { ), ), onTap: () { - Navigator.of(context).push(MaterialPageRoute(builder: (context) { - return VideoDetailsComments( - author: widget.vm.author, permlink: widget.vm.permlink); - })); + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) { + return VideoDetailsComments( + author: widget.vm.author, permlink: widget.vm.permlink); + }, + ), + ); }, ); } @@ -335,6 +381,9 @@ class _VideoDetailsScreenState extends State { // container list view - recommendations Widget videoRecommendationListItem(VideoRecommendationItem item) { + double? payoutAmount = payoutData["${item.owner}/${item.mediaid}"]?.payout; + int? upVotes = payoutData["${item.owner}/${item.mediaid}"]?.upVotes; + int? downVotes = payoutData["${item.owner}/${item.mediaid}"]?.downVotes; return ListTileVideo( placeholder: 'assets/branding/three_speak_logo.png', url: item.image, @@ -348,9 +397,9 @@ class _VideoDetailsScreenState extends State { user: item.owner, permlink: item.mediaid, shouldResize: false, - downVotes: item.downVotes, - upVotes: item.downVotes, - payout: item.payout, + downVotes: downVotes, + upVotes: upVotes, + payout: payoutAmount, ); } diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index 71fe0017..75dce402 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -38,26 +38,6 @@ class ListTileVideo extends StatefulWidget { } class _ListTileVideoState extends State { - // double? payout; - // int? upVotes; - // int? downVotes; - // - // @override - // void initState() { - // super.initState(); - // if (widget.payout == null && - // widget.upVotes == null && - // widget.downVotes == null) { - // fetchHiveInfo(); - // } else { - // setState(() { - // payout = widget.payout; - // upVotes = widget.upVotes; - // downVotes = widget.downVotes; - // }); - // } - // } - Widget _errorIndicator() { return Container( height: 220, @@ -96,40 +76,6 @@ class _ListTileVideoState extends State { ); } - // fetch hive info - // void fetchHiveInfo() async { - // var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); - // request.body = json.encode({ - // "id": 1, - // "jsonrpc": "2.0", - // "method": "bridge.get_discussion", - // "params": { - // "author": widget.user, - // "permlink": widget.permlink, - // "observer": "" - // } - // }); - // http.StreamedResponse response = await request.send(); - // if (response.statusCode == 200) { - // var string = await response.stream.bytesToString(); - // var result = HivePostInfo.fromJsonString(string) - // .result - // .resultData - // .where((element) => element.permlink == widget.permlink) - // .first; - // setState(() { - // payout = result.payout; - // var upVotes = result.activeVotes.where((e) => e.rshares > 0).length; - // var downVotes = result.activeVotes.where((e) => e.rshares < 0).length; - // this.upVotes = upVotes; - // this.downVotes = downVotes; - // widget.hiveInfo(result.payout, upVotes, downVotes); - // }); - // } else { - // print(response.reasonPhrase); - // } - // } - Widget _hivePayoutLoader() { String priceAndVotes = (widget.payout != null && widget.upVotes != null && diff --git a/pubspec.lock b/pubspec.lock index 3b5b2ab7..cb597fed 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -36,6 +36,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.8.2" + base_x: + dependency: transitive + description: + name: base_x + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" boolean_selector: dependency: transitive description: @@ -43,6 +50,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + bs58: + dependency: "direct main" + description: + name: bs58 + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + bs58check: + dependency: "direct main" + description: + name: bs58check + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" build: dependency: transitive description: @@ -156,7 +177,7 @@ packages: source: hosted version: "3.0.1" crypto: - dependency: transitive + dependency: "direct main" description: name: crypto url: "https://pub.dartlang.org" @@ -183,6 +204,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.3" + elliptic: + dependency: "direct main" + description: + name: elliptic + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.8" fake_async: dependency: transitive description: @@ -296,6 +324,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + hex: + dependency: "direct main" + description: + name: hex + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" html: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 469e8b9f..8c737778 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,13 +28,18 @@ environment: # versions available, run `flutter pub outdated`. dependencies: adaptive_action_sheet: ^2.0.1 + bs58: ^1.0.2 + bs58check: ^1.0.2 chewie: ^1.3.0 + crypto: ^3.0.2 + elliptic: ^0.3.8 firebase_core: ^1.12.0 flutter: sdk: flutter flutter_dotenv: ^5.0.2 flutter_markdown: ^0.6.9 font_awesome_flutter: ^10.1.0 + hex: ^0.2.0 http: ^0.13.4 intl: ^0.17.0 json_annotation: ^4.4.0 From 576abb856a04c7313d37284d93deadc329d872d1 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 3 May 2022 09:29:03 +0530 Subject: [PATCH 063/466] login works fine for iOS. --- .DS_Store | Bin 6148 -> 6148 bytes .flutter-plugins | 5 + .flutter-plugins-dependencies | 2 +- .idea/Android-App.iml | 18 ++ .idea/libraries/Dart_Packages.xml | 48 ++++++ .idea/libraries/Flutter_Plugins.xml | 2 + .packages | 8 +- android/.idea/gradle.xml | 3 +- ios/Podfile.lock | 6 + ios/Runner.xcodeproj/project.pbxproj | 14 +- ios/Runner/AcelaWebViewController.swift | 9 +- .../Bridges/{ => Auth}/AuthBridge.swift | 4 +- .../Auth/ValidateHiveKeyResponse.swift | 33 ++++ lib/main.dart | 58 ++++--- lib/src/bloc/server.dart | 11 ++ .../models/login/login_bridge_response.dart | 35 ++++ .../models/user_stream/hive_user_stream.dart | 11 ++ .../screens/drawer_screen/drawer_screen.dart | 17 +- lib/src/screens/login/login_screen.dart | 99 ++++++++--- .../screens/my_account/my_account_screen.dart | 53 ++++++ lib/src/widgets/list_tile_video.dart | 162 ++++++++---------- pubspec.lock | 42 +++++ pubspec.yaml | 1 + 23 files changed, 493 insertions(+), 148 deletions(-) rename ios/Runner/Bridges/{ => Auth}/AuthBridge.swift (95%) create mode 100644 ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift create mode 100644 lib/src/models/login/login_bridge_response.dart create mode 100644 lib/src/models/user_stream/hive_user_stream.dart create mode 100644 lib/src/screens/my_account/my_account_screen.dart diff --git a/.DS_Store b/.DS_Store index 4f30f963d192ba728c5e4a2764e937e761516057..aa38b5f10ddb820cfa227fe34955814c679270da 100644 GIT binary patch delta 85 zcmZoMXfc=|#>B`mu~2NHo}wrd0|Nsi1A_oVaY0f}eiD$kBdK6w;qu7_A}pJiGbONY lUcfwqaWgvyKL=3L=84STnJ4p$SaJXrg7h(M4iMSG3;>5t6lVYc delta 233 zcmZoMXfc=|#>B)qu~2NHo}wrl0|Nsi1A_nqLlHwFLjglUPP$?6=8ufa8S6n(91NKZ zc|e$oES;R6TL6@U0Sq;{`7SO=Ir&LI1sq$&=6{moKjH{tqnnkRpMpo76vEPi48ve# mOE>c{CbMp4=iui6dIad$@640=MJzdh{s1BdhRp#YTbKbN$TFb- diff --git a/.flutter-plugins b/.flutter-plugins index 62bd2083..2cdb7b9f 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,6 +1,11 @@ # This is a generated file; do not edit or check into version control. firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/ firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/ +flutter_secure_storage=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/ +flutter_secure_storage_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/ +flutter_secure_storage_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/ +flutter_secure_storage_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/ +flutter_secure_storage_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/ share_plus=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/ share_plus_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/ share_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index ec8e6066..611dd7fb 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-05-01 09:30:15.778030","version":"2.10.5"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-05-03 09:15:50.560456","version":"2.10.5"} \ No newline at end of file diff --git a/.idea/Android-App.iml b/.idea/Android-App.iml index d43ea6cc..118e4c03 100644 --- a/.idea/Android-App.iml +++ b/.idea/Android-App.iml @@ -24,6 +24,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 4563ba56..15f354c7 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -289,6 +289,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -878,6 +920,12 @@ + + + + + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 0bcd67e4..8c00a45f 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -23,6 +23,8 @@ + + diff --git a/.packages b/.packages index 731e6617..42ab9a8f 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-05-01 07:51:09.046162. +# Generated by pub on 2022-05-01 19:54:52.871333. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ @@ -45,6 +45,12 @@ flutter:file:///Applications/flutter/flutter/packages/flutter/lib/ flutter_dotenv:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_dotenv-5.0.2/lib/ flutter_lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib/ flutter_markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_markdown-0.6.10/lib/ +flutter_secure_storage:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/lib/ +flutter_secure_storage_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/lib/ +flutter_secure_storage_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/lib/ +flutter_secure_storage_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_platform_interface-1.0.0/lib/ +flutter_secure_storage_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/lib/ +flutter_secure_storage_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/lib/ flutter_test:file:///Applications/flutter/flutter/packages/flutter_test/lib/ flutter_web_plugins:file:///Applications/flutter/flutter/packages/flutter_web_plugins/lib/ font_awesome_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/font_awesome_flutter-10.1.0/lib/ diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml index 46e443fd..26bdbfa0 100644 --- a/android/.idea/gradle.xml +++ b/android/.idea/gradle.xml @@ -10,8 +10,9 @@ + + + + + + @@ -688,6 +695,13 @@ + + + + + + @@ -905,6 +919,7 @@ + @@ -974,6 +989,7 @@ + diff --git a/.packages b/.packages index e0be9aaf..b316390e 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-05-22 11:01:09.000807. +# Generated by pub on 2022-05-24 10:33:08.585480. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ @@ -29,6 +29,7 @@ clock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cl code_builder:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/code_builder-4.1.0/lib/ collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.16.0/lib/ convert:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/convert-3.0.1/lib/ +cross_file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cross_file-0.3.3/lib/ crypto:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.2/lib/ csslib:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.17.1/lib/ cupertino_icons:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.4/lib/ @@ -102,6 +103,7 @@ term_glyph:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.o test_api:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.9/lib/ timeago:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timeago-3.2.2/lib/ timing:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timing-1.0.0/lib/ +tus_client:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/tus_client-1.0.2/lib/ typed_data:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib/ universal_io:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/universal_io-2.0.4/lib/ url_launcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.1.0/lib/ diff --git a/ios/Podfile b/ios/Podfile index 6e17546b..ea9d9b81 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -31,7 +31,6 @@ target 'Runner' do use_frameworks! use_modular_headers! pod 'FYVideoCompressor' - pod 'TUSKit' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3ed3f59b..2c05d039 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -33,7 +33,6 @@ PODS: - PromisesObjC (2.1.0) - share_plus (0.0.1): - Flutter - - TUSKit (3.1.2) - url_launcher_ios (0.0.1): - Flutter - video_player_avfoundation (0.0.1): @@ -47,7 +46,6 @@ DEPENDENCIES: - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - FYVideoCompressor - share_plus (from `.symlinks/plugins/share_plus/ios`) - - TUSKit - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) - wakelock (from `.symlinks/plugins/wakelock/ios`) @@ -62,7 +60,6 @@ SPEC REPOS: - GoogleUtilities - nanopb - PromisesObjC - - TUSKit EXTERNAL SOURCES: firebase_core: @@ -93,11 +90,10 @@ SPEC CHECKSUMS: nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 PromisesObjC: 99b6f43f9e1044bd87a95a60beff28c2c44ddb72 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 - TUSKit: 0dedde8a33b84c3b7248a24bc25b41c47797afa8 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f -PODFILE CHECKSUM: d7b9207ef5ec0d27f2f43c2baddc012d3c0af642 +PODFILE CHECKSUM: c47b194cb97680e602c9d704f278cff245139eb7 COCOAPODS: 1.11.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index bfb11f18..caaef5ba 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -388,7 +388,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -417,7 +417,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -464,7 +464,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -522,7 +522,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -553,7 +553,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -577,7 +577,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index dda395d7..ad96e8cd 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -21,4 +21,10 @@ import Flutter GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + +// override func applicationDidBecomeActive(_ application: UIApplication) { +// if (TSSocket.shared.tusClient == nil) { +// TSSocket.shared.connect() +// } +// } } diff --git a/ios/Runner/Bridges/Encoder/EncoderBridge.swift b/ios/Runner/Bridges/Encoder/EncoderBridge.swift index 68ea8acf..b69f966f 100644 --- a/ios/Runner/Bridges/Encoder/EncoderBridge.swift +++ b/ios/Runner/Bridges/Encoder/EncoderBridge.swift @@ -17,6 +17,7 @@ class EncoderBridge: NSObject { var acela: AcelaWebViewController? var controller: FlutterViewController? let picker = UIImagePickerController() + var result: FlutterResult? func initiate(controller: FlutterViewController, window: UIWindow?, acela: AcelaWebViewController?) { self.window = window @@ -49,57 +50,65 @@ class EncoderBridge: NSObject { details: nil)) return } -// acela.validatePostingKey(username: username, postingKey: postingKey) { response in -// guard -// let data = response.data(using: .utf8), -// let object = try? JSONDecoder().decode(ValidateHiveKeyResponse.self, from: data), -// object.valid == true -// else { -// result(response) -// return -// } -// showPicker() -// } - showPicker() + acela.validatePostingKey(username: username, postingKey: postingKey) { [weak self] response in + guard + let data = response.data(using: .utf8), + let object = try? JSONDecoder().decode(ValidateHiveKeyResponse.self, from: data), + object.valid == true + else { + result(response) + return + } + self?.showPicker(result: result) + } } - func showPicker() { + func showPicker(result: @escaping FlutterResult) { if #available(iOS 14, *) { PHPhotoLibrary.requestAuthorization(for: .readWrite) { (status) in DispatchQueue.main.async { - self.showUI(for: status) + self.showUI(for: status, result: result) } } } else { - showVideoPicker() + showVideoPicker(result: result) } } - func showUI(for status: PHAuthorizationStatus) { + func showUI(for status: PHAuthorizationStatus, result: @escaping FlutterResult) { switch status { case .authorized: - showVideoPicker() + showVideoPicker(result: result) case .limited: - showVideoPicker() + showVideoPicker(result: result) case .restricted: - showVideoPicker() + showVideoPicker(result: result) case .denied: - print("Denied") + result(FlutterError(code: "ERROR", + message: "Please provide access. Go to Settings > Acela > Photos > Selected Photos / All Photos", + details: nil)) case .notDetermined: - print("Denied") + result(FlutterError(code: "ERROR", + message: "Please provide access. Go to Settings > Acela > Photos > Selected Photos / All Photos.", + details: nil)) break @unknown default: break } } - func showVideoPicker() { + func showVideoPicker(result: @escaping FlutterResult) { if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { picker.sourceType = .photoLibrary picker.mediaTypes = ["public.movie"] picker.allowsEditing = false picker.delegate = self controller?.present(picker, animated: true, completion: nil) + self.result = result + } else { + result(FlutterError(code: "ERROR", + message: "Please provide access. Go to Settings > Acela > Photos > Selected Photos / All Photos.", + details: nil)) } } @@ -118,6 +127,7 @@ class EncoderBridge: NSObject { export?.outputFileType = AVFileType.mp4 export?.exportAsynchronously(completionHandler: { debugPrint("DocDir url - \(docDirFileUrl.absoluteString)") + self.result?(docDirFileUrl.absoluteString) }) } } @@ -133,15 +143,19 @@ extension EncoderBridge: UIImagePickerControllerDelegate, UINavigationController picker.dismiss(animated: true) { debugPrint("URL of media is \(url.debugDescription)") self.convertToMP4(url: url) - // self.encodingOptions(url) - // self.performSegue(withIdentifier: "encode", sender: url) } } else { picker.dismiss(animated: true, completion: nil) + result?(FlutterError(code: "ERROR", + message: "Selection of media is not a video.", + details: nil)) } } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { picker.dismiss(animated: true, completion: nil) + result?(FlutterError(code: "ERROR", + message: "You cancelled selection of videos.", + details: nil)) } } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 857ffd50..d147d433 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -29,6 +31,8 @@ NSAllowsArbitraryLoads + NSPhotoLibraryUsageDescription + Allow access to videos UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -48,7 +52,5 @@ UIViewControllerBasedStatusBarAppearance - NSPhotoLibraryUsageDescription - Allow access to videos diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 577dbe07..00d7b08a 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -1,9 +1,11 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; import 'package:acela/src/screens/search/search_screen.dart'; @@ -14,6 +16,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import 'package:http/http.dart' show get; +import 'package:provider/provider.dart'; class HomeScreen extends StatefulWidget { const HomeScreen( @@ -165,14 +168,18 @@ class _HomeScreenState extends State { }, payout); } - Widget _fab() { + Widget _fab(HiveUserData user) { return FloatingActionButton( onPressed: () async { - // final String result = - await platform.invokeMethod('video', { - 'username': 'a', - 'postingKey': 'b', - }); + try { + final String result = await platform.invokeMethod('video', { + 'username': user.username, + 'postingKey': user.postingKey, + }); + log('Result is $result'); + } catch (e) { + showError(e.toString()); + } }, child: const Icon(Icons.add), ); @@ -180,6 +187,7 @@ class _HomeScreenState extends State { @override Widget build(BuildContext context) { + var user = Provider.of(context); return Scaffold( appBar: AppBar( title: Text(widget.title), @@ -195,7 +203,7 @@ class _HomeScreenState extends State { ), body: _screen(), drawer: widget.showDrawer ? const DrawerScreen() : null, - floatingActionButton: _fab(), + floatingActionButton: user == null ? null : _fab(user), ); } } diff --git a/pubspec.lock b/pubspec.lock index 238bf309..81a65364 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -176,6 +176,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" + cross_file: + dependency: transitive + description: + name: cross_file + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.3" crypto: dependency: "direct main" description: @@ -679,6 +686,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" + tus_client: + dependency: "direct main" + description: + name: tus_client + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 440a81c6..620ad9bf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+10 +version: 1.0.0+11 environment: sdk: ">=2.15.1 <3.0.0" @@ -47,6 +47,7 @@ dependencies: provider: ^6.0.2 share_plus: ^4.0.4 timeago: ^3.1.0 + tus_client: ^1.0.2 url_launcher: ^6.0.20 video_player: ^2.2.14 video_player_web_hls: ^0.1.11+3 From c1dea8eb89e50f7db58cfe7172e243d9f3d46d01 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 24 May 2022 18:35:10 +0530 Subject: [PATCH 071/466] work in progress for decode memo. --- ios/Runner/AcelaWebViewController.swift | 1 + ios/Runner/Bridges/Auth/AuthBridge.swift | 49 +++++++++--- ios/Runner/public/index.html | 78 +++++++++++++------ lib/main.dart | 5 +- .../models/user_stream/hive_user_stream.dart | 2 + .../video_upload_login_response.dart | 31 ++++++++ lib/src/screens/home_screen/home_screen.dart | 65 ++++++++++++++-- lib/src/screens/login/login_screen.dart | 2 + 8 files changed, 190 insertions(+), 43 deletions(-) create mode 100644 lib/src/models/video_upload/video_upload_login_response.dart diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index e8a19691..d751e280 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -15,6 +15,7 @@ class AcelaWebViewController: UIViewController { var webView: WKWebView? var didFinish = false var postingKeyValidationHandler: ((String) -> Void)? + var decryptTokenHandler: ((String) -> Void)? override func viewDidLoad() { super.viewDidLoad() diff --git a/ios/Runner/Bridges/Auth/AuthBridge.swift b/ios/Runner/Bridges/Auth/AuthBridge.swift index 639d2e44..77fc12eb 100644 --- a/ios/Runner/Bridges/Auth/AuthBridge.swift +++ b/ios/Runner/Bridges/Auth/AuthBridge.swift @@ -22,16 +22,29 @@ class AuthBridge { authChannel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in // Note: this method is invoked on the UI thread. - guard - call.method == "validate", - let arguments = call.arguments as? NSDictionary, - let username = arguments ["username"] as? String, - let password = arguments["postingKey"] as? String - else { - result(FlutterMethodNotImplemented) - return + switch (call.method) { + case "validate": + guard + let arguments = call.arguments as? NSDictionary, + let username = arguments ["username"] as? String, + let password = arguments["postingKey"] as? String + else { + result(FlutterMethodNotImplemented) + return + } + self?.authenticate(username: username, postingKey: password, result: result) + case "encryptedToken": + guard + let arguments = call.arguments as? NSDictionary, + let username = arguments ["username"] as? String, + let password = arguments["postingKey"] as? String, + let encryptedToken = arguments["encryptedToken"] as? String + else { + result(FlutterMethodNotImplemented) + return + } + self?.decryptMemo(username: username, postingKey: password, encryptedMemo: encryptedToken, result: result) } - self?.authenticate(username: username, postingKey: password, result: result) }) } @@ -46,4 +59,22 @@ class AuthBridge { result(response) } } + + private func decryptMemo( + username: String, + postingKey: String, + encryptedMemo: String, + result: @escaping FlutterResult + ) { + guard let acela = acela else { + result(FlutterError(code: "ERROR", + message: "Error setting up Hive", + details: nil)) + return + } + acela. + acela.validatePostingKey(username: username, postingKey: postingKey) { response in + result(response) + } + } } diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index 85087d0d..7b973c1e 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -13,31 +13,63 @@ diff --git a/lib/main.dart b/lib/main.dart index 31a21ca5..e7cc60b3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -46,15 +46,14 @@ class _MyAppState extends State { void loadData() async { String? username = await storage.read(key: 'username'); String? postingKey = await storage.read(key: 'postingKey'); + String? cookie = await storage.read(key: 'cookie'); if (username != null && postingKey != null && username.isNotEmpty && postingKey.isNotEmpty) { server.updateHiveUserData( HiveUserData( - username: username, - postingKey: postingKey, - ), + username: username, postingKey: postingKey, cookie: cookie), ); } } diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index 5cbbf9d1..810e5e39 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -1,10 +1,12 @@ class HiveUserData { String username; String postingKey; + String? cookie; // String avatar; // https://images.hive.blog/u/sagarkothari88/avatar HiveUserData({ required this.username, required this.postingKey, + required this.cookie, }); } diff --git a/lib/src/models/video_upload/video_upload_login_response.dart b/lib/src/models/video_upload/video_upload_login_response.dart new file mode 100644 index 00000000..312be9cb --- /dev/null +++ b/lib/src/models/video_upload/video_upload_login_response.dart @@ -0,0 +1,31 @@ +import 'dart:convert'; + +import 'package:acela/src/utils/safe_convert.dart'; + +class VideoUploadLoginResponse { + final bool? banned; + final String? memo; + final String? userId; + final String? network; + final String? error; + + VideoUploadLoginResponse({ + required this.banned, + required this.memo, + required this.userId, + required this.network, + required this.error, + }); + + factory VideoUploadLoginResponse.fromJson(Map? json) => + VideoUploadLoginResponse( + banned: asBool(json, 'banned'), + memo: asString(json, 'memo'), + userId: asString(json, 'user_id'), + network: asString(json, 'network'), + error: asString(json, 'error'), + ); + + factory VideoUploadLoginResponse.fromJsonString(String jsonString) => + VideoUploadLoginResponse.fromJson(json.decode(jsonString)); +} diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 00d7b08a..7434a09b 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -6,6 +6,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/models/video_upload/video_upload_login_response.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; import 'package:acela/src/screens/search/search_screen.dart'; @@ -89,14 +90,14 @@ class _HomeScreenState extends State { setState(() { isLoading = false; items = list; - var i = 0; - Timer.periodic(const Duration(seconds: 1), (timer) { - fetchHiveInfo(list[i].author, list[i].permlink); - i += 1; - if (i == list.length) { - timer.cancel(); - } - }); + }); + var i = 0; + Timer.periodic(const Duration(seconds: 1), (timer) { + fetchHiveInfo(list[i].author, list[i].permlink); + i += 1; + if (i == list.length) { + timer.cancel(); + } }); } else { showError('Status code ${response.statusCode}'); @@ -168,6 +169,52 @@ class _HomeScreenState extends State { }, payout); } + void getAccessToken(HiveUserData user, String encryptedToken) async { + final String result = await platform.invokeMethod('encryptedToken', { + 'username': user.username, + 'postingKey': user.postingKey, + 'encryptedToken': encryptedToken, + }); + } + + void getMemo(HiveUserData user) async { + var request = http.Request( + 'GET', + Uri.parse( + 'http://localhost:13050/mobile/login?username=${user.username}')); + if (user.cookie != null) { + Map map = {"cookie": user.cookie!}; + request.headers.addAll(map); + } + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + var loginResponse = VideoUploadLoginResponse.fromJsonString(string); + if (loginResponse.error != null) { + showError('Error - ${loginResponse.error}'); + setState(() { + isLoading = false; + }); + } else if (loginResponse.memo != null) { + getAccessToken(user, loginResponse.memo!); + } else if (loginResponse.network == "hive" && + loginResponse.banned == true && + loginResponse.userId != null) { + } else { + log('This should never happen. No error, no memo, no user info. How?'); + showError('Something went wrong.'); + setState(() { + isLoading = false; + }); + } + } else { + showError('Status code ${response.statusCode}'); + setState(() { + isLoading = false; + }); + } + } + Widget _fab(HiveUserData user) { return FloatingActionButton( onPressed: () async { @@ -177,6 +224,8 @@ class _HomeScreenState extends State { 'postingKey': user.postingKey, }); log('Result is $result'); + + // http://localhost:13050/mobile/login?username=shaktimaaan } catch (e) { showError(e.toString()); } diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 143d8449..916ac3a6 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -35,10 +35,12 @@ class _LoginScreenState extends State { debugPrint("Successful login"); await storage.write(key: 'username', value: username); await storage.write(key: 'postingKey', value: postingKey); + await storage.delete(key: 'cookie'); server.updateHiveUserData( HiveUserData( username: username, postingKey: postingKey, + cookie: null, ), ); Navigator.of(context).pop(); From 495bbf8133b719bd48f8e1b33710499300ad3b33 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 25 May 2022 16:40:56 +0530 Subject: [PATCH 072/466] Getting the cookie & file URL. --- .flutter-plugins-dependencies | 2 +- ios/Runner/AcelaWebViewController.swift | 24 ++++- ios/Runner/Bridges/Auth/AuthBridge.swift | 4 +- .../Auth/ValidateHiveKeyResponse.swift | 22 +++++ .../Bridges/Encoder/EncoderBridge.swift | 61 +++++++++---- ios/Runner/public/index.html | 4 +- lib/src/models/login/memo_response.dart | 30 +++++++ lib/src/screens/home_screen/home_screen.dart | 90 ++++++++++++++----- 8 files changed, 195 insertions(+), 42 deletions(-) create mode 100644 lib/src/models/login/memo_response.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index e46f0d7f..c46c9ec2 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-05-24 11:17:31.566617","version":"3.0.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-05-25 16:07:36.328368","version":"3.0.1"} \ No newline at end of file diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index d751e280..9ddd32b7 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -39,6 +39,18 @@ class AcelaWebViewController: UIViewController { self.webView?.evaluateJavaScript("validateHiveKey('\(username)', '\(postingKey)')") } } + + func decryptMemo( + username: String, + postingKey: String, + encryptedMemo: String, + handler: @escaping (String) -> Void + ) { + decryptTokenHandler = handler + OperationQueue.main.addOperation { + self.webView?.evaluateJavaScript("decryptMemo('\(username)', '\(postingKey)', '\(encryptedMemo)')") + } + } } extension AcelaWebViewController: WKNavigationDelegate { @@ -66,9 +78,19 @@ extension AcelaWebViewController: WKScriptMessageHandler { else { return } debugPrint("Is it valid? \(isValid ? "TRUE" : "FALSE")") debugPrint("account name is \(accountName)") - debugPrint("posting key is \(postingKey)") debugPrint("Error is \(error)") postingKeyValidationHandler?(response) + case "decryptedMemo": + guard + let accountName = dict["accountName"] as? String, + let error = dict["error"] as? String, + let decrypted = dict["decrypted"] as? String, + let response = DecryptMemoResponse.jsonStringFrom(dict: dict) + else { return } + debugPrint("account name is \(accountName)") + debugPrint("Error is \(error)") + debugPrint("decrypted is \(decrypted)") + decryptTokenHandler?(response) default: debugPrint("Do nothing here.") } } diff --git a/ios/Runner/Bridges/Auth/AuthBridge.swift b/ios/Runner/Bridges/Auth/AuthBridge.swift index 77fc12eb..c16a9c63 100644 --- a/ios/Runner/Bridges/Auth/AuthBridge.swift +++ b/ios/Runner/Bridges/Auth/AuthBridge.swift @@ -44,6 +44,7 @@ class AuthBridge { return } self?.decryptMemo(username: username, postingKey: password, encryptedMemo: encryptedToken, result: result) + default: debugPrint("do nothing") } }) } @@ -72,8 +73,7 @@ class AuthBridge { details: nil)) return } - acela. - acela.validatePostingKey(username: username, postingKey: postingKey) { response in + acela.decryptMemo(username: username, postingKey: postingKey, encryptedMemo: encryptedMemo) { response in result(response) } } diff --git a/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift b/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift index 80aaf070..1a951fe2 100644 --- a/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift +++ b/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift @@ -31,3 +31,25 @@ struct ValidateHiveKeyResponse: Codable { return dataString } } + +struct DecryptMemoResponse: Codable { + let accountName: String + let decrypted: String + let error: String + + static func jsonStringFrom(dict: [String: AnyObject]) -> String? { + guard + let accountName = dict["accountName"] as? String, + let error = dict["error"] as? String, + let decrypted = dict["decrypted"] as? String + else { return nil } + let response = DecryptMemoResponse( + accountName: accountName, + decrypted: decrypted, + error: error + ) + guard let data = try? JSONEncoder().encode(response) else { return nil } + guard let dataString = String(data: data, encoding: .utf8) else { return nil } + return dataString + } +} diff --git a/ios/Runner/Bridges/Encoder/EncoderBridge.swift b/ios/Runner/Bridges/Encoder/EncoderBridge.swift index b69f966f..40dd9e7a 100644 --- a/ios/Runner/Bridges/Encoder/EncoderBridge.swift +++ b/ios/Runner/Bridges/Encoder/EncoderBridge.swift @@ -77,23 +77,23 @@ class EncoderBridge: NSObject { func showUI(for status: PHAuthorizationStatus, result: @escaping FlutterResult) { switch status { - case .authorized: - showVideoPicker(result: result) - case .limited: - showVideoPicker(result: result) - case .restricted: - showVideoPicker(result: result) - case .denied: + case .authorized: + showVideoPicker(result: result) + case .limited: + showVideoPicker(result: result) + case .restricted: + showVideoPicker(result: result) + case .denied: result(FlutterError(code: "ERROR", message: "Please provide access. Go to Settings > Acela > Photos > Selected Photos / All Photos", details: nil)) - case .notDetermined: + case .notDetermined: result(FlutterError(code: "ERROR", message: "Please provide access. Go to Settings > Acela > Photos > Selected Photos / All Photos.", details: nil)) - break - @unknown default: - break + break + @unknown default: + break } } @@ -127,11 +127,40 @@ class EncoderBridge: NSObject { export?.outputFileType = AVFileType.mp4 export?.exportAsynchronously(completionHandler: { debugPrint("DocDir url - \(docDirFileUrl.absoluteString)") - self.result?(docDirFileUrl.absoluteString) + let asset = AVAsset(url: docDirFileUrl) + let duration = asset.duration + let durationTime = CMTimeGetSeconds(duration) + debugPrint("Video duration is in seconds - \(durationTime) seconds") + do { + let attr = try FileManager.default.attributesOfItem(atPath: docDirFilePath) + let fileSize = attr[FileAttributeKey.size] as! UInt64 + debugPrint("Video file size is - \(fileSize)") + let responseString = VideoDataResponse.jsonStringFrom(size: Double(fileSize), duration: Double(durationTime), oFilename: docDirFileUrl.absoluteString) + self.result?(responseString) + } catch { + print("Error: \(error)") + } }) } } +struct VideoDataResponse: Codable { + let size: Double + let duration: Double + let oFilename: String + + static func jsonStringFrom(size: Double, duration: Double, oFilename: String) -> String? { + let response = VideoDataResponse( + size: size, + duration: duration, + oFilename: oFilename + ) + guard let data = try? JSONEncoder().encode(response) else { return nil } + guard let dataString = String(data: data, encoding: .utf8) else { return nil } + return dataString + } +} + extension EncoderBridge: UIImagePickerControllerDelegate, UINavigationControllerDelegate { func imagePickerController( _ picker: UIImagePickerController, @@ -147,15 +176,15 @@ extension EncoderBridge: UIImagePickerControllerDelegate, UINavigationController } else { picker.dismiss(animated: true, completion: nil) result?(FlutterError(code: "ERROR", - message: "Selection of media is not a video.", - details: nil)) + message: "Selection of media is not a video.", + details: nil)) } } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { picker.dismiss(animated: true, completion: nil) result?(FlutterError(code: "ERROR", - message: "You cancelled selection of videos.", - details: nil)) + message: "You cancelled selection of videos.", + details: nil)) } } diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index 7b973c1e..ee17a755 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -53,7 +53,7 @@ console.log("PubWif: ", pubWif); const Valid = hive.auth.wifIsValid(postingKey, pubWif); console.log(`is valid ${Valid}`); - var decrypted = hive.memo.decode(postingKey, publicKey, encrypted); + var decrypted = hive.memo.decode(postingKey, encrypted); window.webkit.messageHandlers.acela.postMessage({ type: "decryptedMemo", accountName: accountName, @@ -66,7 +66,7 @@ window.webkit.messageHandlers.acela.postMessage({ type: "decryptedMemo", accountName: accountName, - decrypted: null, + decrypted: "", error: err.message, }); }); diff --git a/lib/src/models/login/memo_response.dart b/lib/src/models/login/memo_response.dart new file mode 100644 index 00000000..31201a05 --- /dev/null +++ b/lib/src/models/login/memo_response.dart @@ -0,0 +1,30 @@ +import 'dart:convert'; + +import 'package:acela/src/utils/safe_convert.dart'; + +class MemoResponse { + final String error; + final String accountName; + final String decrypted; + + MemoResponse({ + this.error = "", + this.accountName = "", + this.decrypted = "", + }); + + factory MemoResponse.fromJson(Map? json) => MemoResponse( + error: asString(json, 'error'), + accountName: asString(json, 'accountName'), + decrypted: asString(json, 'decrypted'), + ); + + factory MemoResponse.fromJsonString(String jsonString) => + MemoResponse.fromJson(json.decode(jsonString)); + + Map toJson() => { + 'error': error, + 'accountName': accountName, + 'decrypted': decrypted, + }; +} diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 7434a09b..b9510df3 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -5,6 +5,7 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/models/login/memo_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_upload/video_upload_login_response.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; @@ -15,6 +16,7 @@ import 'package:acela/src/screens/video_details_screen/video_details_screen.dart import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:http/http.dart' as http; import 'package:http/http.dart' show get; import 'package:provider/provider.dart'; @@ -169,15 +171,25 @@ class _HomeScreenState extends State { }, payout); } - void getAccessToken(HiveUserData user, String encryptedToken) async { + Future getAccessToken( + HiveUserData user, String encryptedToken) async { + const platform = MethodChannel('com.example.acela/auth'); final String result = await platform.invokeMethod('encryptedToken', { 'username': user.username, 'postingKey': user.postingKey, 'encryptedToken': encryptedToken, }); + var memo = MemoResponse.fromJsonString(result); + if (memo.error.isNotEmpty) { + showError('Error ${memo.error}'); + throw memo.error; + } else if (memo.decrypted.isEmpty) { + throw 'Decrypted memo is empty'; + } + return memo.decrypted.replaceFirst("#", ''); } - void getMemo(HiveUserData user) async { + Future getValidCookie(HiveUserData user) async { var request = http.Request( 'GET', Uri.parse( @@ -190,28 +202,66 @@ class _HomeScreenState extends State { if (response.statusCode == 200) { var string = await response.stream.bytesToString(); var loginResponse = VideoUploadLoginResponse.fromJsonString(string); - if (loginResponse.error != null) { - showError('Error - ${loginResponse.error}'); - setState(() { - isLoading = false; - }); + if (loginResponse.error != null && loginResponse.error!.isNotEmpty) { + throw 'Error - ${loginResponse.error}'; } else if (loginResponse.memo != null) { - getAccessToken(user, loginResponse.memo!); + var token = await getAccessToken(user, loginResponse.memo!); + var url = + 'http://localhost:13050/mobile/login?username=${user.username}&access_token=$token'; + var request = http.Request('GET', Uri.parse(url)); + http.StreamedResponse response = await request.send(); + var string = await response.stream.bytesToString(); + var tokenResponse = VideoUploadLoginResponse.fromJsonString(string); + var cookie = response.headers['set-cookie']; + if (tokenResponse.error != null && tokenResponse.error!.isNotEmpty) { + throw 'Error - ${tokenResponse.error}'; + } else if (tokenResponse.network == "hive" && + tokenResponse.banned != true && + tokenResponse.userId != null && + cookie != null && + cookie.isNotEmpty) { + const storage = FlutterSecureStorage(); + await storage.write(key: 'cookie', value: cookie); + var newData = HiveUserData( + username: user.username, + postingKey: user.postingKey, + cookie: cookie, + ); + server.updateHiveUserData(newData); + return cookie; + } else { + log('This should never happen. No error, no user info. How?'); + throw 'Something went wrong.'; + } } else if (loginResponse.network == "hive" && - loginResponse.banned == true && - loginResponse.userId != null) { + loginResponse.banned != true && + loginResponse.userId != null && + user.cookie != null) { + return user.cookie!; } else { log('This should never happen. No error, no memo, no user info. How?'); - showError('Something went wrong.'); - setState(() { - isLoading = false; - }); + throw 'Something went wrong.'; + } + } else if (response.statusCode == 500) { + var string = await response.stream.bytesToString(); + var errorResponse = VideoUploadLoginResponse.fromJsonString(string); + if (errorResponse.error != null && + errorResponse.error!.isNotEmpty && + errorResponse.error == 'session expired') { + const storage = FlutterSecureStorage(); + await storage.delete(key: 'cookie'); + var newData = HiveUserData( + username: user.username, + postingKey: user.postingKey, + cookie: null, + ); + server.updateHiveUserData(newData); + return await getValidCookie(newData); + } else { + throw 'Status code ${response.statusCode}'; } } else { - showError('Status code ${response.statusCode}'); - setState(() { - isLoading = false; - }); + throw 'Status code ${response.statusCode}'; } } @@ -224,8 +274,8 @@ class _HomeScreenState extends State { 'postingKey': user.postingKey, }); log('Result is $result'); - - // http://localhost:13050/mobile/login?username=shaktimaaan + var cookie = await getValidCookie(user); + log('Cookie is $cookie'); } catch (e) { showError(e.toString()); } From 143b126d8501d302158b2e8a369f5780c93082f7 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 26 May 2022 07:56:38 +0530 Subject: [PATCH 073/466] Video prepare in progress. --- .flutter-plugins-dependencies | 2 +- .../Bridges/Encoder/EncoderBridge.swift | 12 +- .../video_upload_prepare_response.dart | 228 ++++++++++++++++++ lib/src/screens/home_screen/home_screen.dart | 169 +++---------- lib/src/utils/communicator.dart | 159 ++++++++++++ 5 files changed, 425 insertions(+), 145 deletions(-) create mode 100644 lib/src/models/video_upload/video_upload_prepare_response.dart create mode 100644 lib/src/utils/communicator.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index c46c9ec2..3c5f7948 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-05-25 16:07:36.328368","version":"3.0.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-05-26 07:50:06.433795","version":"3.0.1"} \ No newline at end of file diff --git a/ios/Runner/Bridges/Encoder/EncoderBridge.swift b/ios/Runner/Bridges/Encoder/EncoderBridge.swift index 40dd9e7a..36fa29e4 100644 --- a/ios/Runner/Bridges/Encoder/EncoderBridge.swift +++ b/ios/Runner/Bridges/Encoder/EncoderBridge.swift @@ -135,7 +135,7 @@ class EncoderBridge: NSObject { let attr = try FileManager.default.attributesOfItem(atPath: docDirFilePath) let fileSize = attr[FileAttributeKey.size] as! UInt64 debugPrint("Video file size is - \(fileSize)") - let responseString = VideoDataResponse.jsonStringFrom(size: Double(fileSize), duration: Double(durationTime), oFilename: docDirFileUrl.absoluteString) + let responseString = VideoDataResponse.jsonStringFrom(size: Int(fileSize), duration: Int(durationTime), oFilename: "\(fileName).mp4", path: docDirFileUrl.absoluteString) self.result?(responseString) } catch { print("Error: \(error)") @@ -145,15 +145,17 @@ class EncoderBridge: NSObject { } struct VideoDataResponse: Codable { - let size: Double - let duration: Double + let size: Int + let duration: Int let oFilename: String + let path: String - static func jsonStringFrom(size: Double, duration: Double, oFilename: String) -> String? { + static func jsonStringFrom(size: Int, duration: Int, oFilename: String, path: String) -> String? { let response = VideoDataResponse( size: size, duration: duration, - oFilename: oFilename + oFilename: oFilename, + path: path ) guard let data = try? JSONEncoder().encode(response) else { return nil } guard let dataString = String(data: data, encoding: .utf8) else { return nil } diff --git a/lib/src/models/video_upload/video_upload_prepare_response.dart b/lib/src/models/video_upload/video_upload_prepare_response.dart new file mode 100644 index 00000000..9f934382 --- /dev/null +++ b/lib/src/models/video_upload/video_upload_prepare_response.dart @@ -0,0 +1,228 @@ +import 'dart:convert'; + +import 'package:acela/src/utils/safe_convert.dart'; + +class VideoUploadPrepareResponse { + final String signedUrl; + final String filename; + final double duration; + final String originalFilename; + final String status; + final VideoUploadInfo video; + final String uploadType; + + VideoUploadPrepareResponse({ + this.signedUrl = "", + this.filename = "", + this.duration = 0.0, + this.originalFilename = "", + this.status = "", + required this.video, + this.uploadType = "", + }); + + factory VideoUploadPrepareResponse.fromJson(Map? json) => + VideoUploadPrepareResponse( + signedUrl: asString(json, 'signed_url'), + filename: asString(json, 'filename'), + duration: asDouble(json, 'duration'), + originalFilename: asString(json, 'original_filename'), + status: asString(json, 'status'), + video: VideoUploadInfo.fromJson(asMap(json, 'video')), + uploadType: asString(json, 'upload_type'), + ); + + factory VideoUploadPrepareResponse.fromJsonString(String jsonString) => + VideoUploadPrepareResponse.fromJson(json.decode(jsonString)); + + Map toJson() => { + 'signed_url': signedUrl, + 'filename': filename, + 'duration': duration, + 'original_filename': originalFilename, + 'status': status, + 'video': video.toJson(), + 'upload_type': uploadType, + }; +} + +class VideoUploadInfo { + final VideoEncoding encoding; + final bool updateSteem; + final bool lowRc; + final bool needsBlockchainUpdate; + final String status; + final String encodingPriceSteem; + final bool paid; + final int encodingProgress; + final String created; + final bool is3CJContent; + final bool isVOD; + final bool isNsfwContent; + final bool declineRewards; + final bool rewardPowerup; + final String language; + final String category; + final bool firstUpload; + final bool indexed; + final int views; + final String hive; + final bool upvoteEligible; + final String publishType; + final String beneficiaries; + final int votePercent; + final bool reducedUpvote; + final bool donations; + final bool postToHiveBlog; + final String id; + final String originalFilename; + final String permlink; + final double duration; + final int size; + final String owner; + final String uploadType; + final int v; + + VideoUploadInfo({ + required this.encoding, + this.updateSteem = false, + this.lowRc = false, + this.needsBlockchainUpdate = false, + this.status = "", + this.encodingPriceSteem = "", + this.paid = false, + this.encodingProgress = 0, + this.created = "", + this.is3CJContent = false, + this.isVOD = false, + this.isNsfwContent = false, + this.declineRewards = false, + this.rewardPowerup = false, + this.language = "", + this.category = "", + this.firstUpload = false, + this.indexed = false, + this.views = 0, + this.hive = "", + this.upvoteEligible = false, + this.publishType = "", + this.beneficiaries = "", + this.votePercent = 0, + this.reducedUpvote = false, + this.donations = false, + this.postToHiveBlog = false, + this.id = "", + this.originalFilename = "", + this.permlink = "", + this.duration = 0.0, + this.size = 0, + this.owner = "", + this.uploadType = "", + this.v = 0, + }); + + factory VideoUploadInfo.fromJson(Map? json) => + VideoUploadInfo( + encoding: VideoEncoding.fromJson(asMap(json, 'encoding')), + updateSteem: asBool(json, 'updateSteem'), + lowRc: asBool(json, 'lowRc'), + needsBlockchainUpdate: asBool(json, 'needsBlockchainUpdate'), + status: asString(json, 'status'), + encodingPriceSteem: asString(json, 'encoding_price_steem'), + paid: asBool(json, 'paid'), + encodingProgress: asInt(json, 'encodingProgress'), + created: asString(json, 'created'), + is3CJContent: asBool(json, 'is3CJContent'), + isVOD: asBool(json, 'isVOD'), + isNsfwContent: asBool(json, 'isNsfwContent'), + declineRewards: asBool(json, 'declineRewards'), + rewardPowerup: asBool(json, 'rewardPowerup'), + language: asString(json, 'language'), + category: asString(json, 'category'), + firstUpload: asBool(json, 'firstUpload'), + indexed: asBool(json, 'indexed'), + views: asInt(json, 'views'), + hive: asString(json, 'hive'), + upvoteEligible: asBool(json, 'upvoteEligible'), + publishType: asString(json, 'publish_type'), + beneficiaries: asString(json, 'beneficiaries'), + votePercent: asInt(json, 'votePercent'), + reducedUpvote: asBool(json, 'reducedUpvote'), + donations: asBool(json, 'donations'), + postToHiveBlog: asBool(json, 'postToHiveBlog'), + id: asString(json, '_id'), + originalFilename: asString(json, 'originalFilename'), + permlink: asString(json, 'permlink'), + duration: asDouble(json, 'duration'), + size: asInt(json, 'size'), + owner: asString(json, 'owner'), + uploadType: asString(json, 'upload_type'), + v: asInt(json, '__v'), + ); + + Map toJson() => { + 'encoding': encoding.toJson(), + 'updateSteem': updateSteem, + 'lowRc': lowRc, + 'needsBlockchainUpdate': needsBlockchainUpdate, + 'status': status, + 'encoding_price_steem': encodingPriceSteem, + 'paid': paid, + 'encodingProgress': encodingProgress, + 'created': created, + 'is3CJContent': is3CJContent, + 'isVOD': isVOD, + 'isNsfwContent': isNsfwContent, + 'declineRewards': declineRewards, + 'rewardPowerup': rewardPowerup, + 'language': language, + 'category': category, + 'firstUpload': firstUpload, + 'indexed': indexed, + 'views': views, + 'hive': hive, + 'upvoteEligible': upvoteEligible, + 'publish_type': publishType, + 'beneficiaries': beneficiaries, + 'votePercent': votePercent, + 'reducedUpvote': reducedUpvote, + 'donations': donations, + 'postToHiveBlog': postToHiveBlog, + '_id': id, + 'originalFilename': originalFilename, + 'permlink': permlink, + 'duration': duration, + 'size': size, + 'owner': owner, + 'upload_type': uploadType, + '__v': v, + }; +} + +class VideoEncoding { + final bool e360; + final bool e480; + final bool e720; + final bool e1080; + + VideoEncoding({ + this.e360 = false, + this.e480 = false, + this.e720 = false, + this.e1080 = false, + }); + + factory VideoEncoding.fromJson(Map? json) => VideoEncoding( + e360: asBool(json, '360'), + e480: asBool(json, '480'), + e720: asBool(json, '720'), + e1080: asBool(json, '1080'), + ); + + Map toJson() => { + '360': 360, + '480': 480, + '720': 720, + '1080': 1080, + }; +} diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index b9510df3..f7ea9065 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -1,23 +1,17 @@ -import 'dart:async'; -import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; -import 'package:acela/src/models/login/memo_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/models/video_upload/video_upload_login_response.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; import 'package:acela/src/screens/search/search_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:http/http.dart' as http; import 'package:http/http.dart' show get; import 'package:provider/provider.dart'; @@ -73,6 +67,7 @@ class _HomeScreenState extends State { List items = []; var isLoading = false; Map payout = {}; + var isFabLoading = false; static const platform = MethodChannel('com.example.acela/encoder'); @@ -94,13 +89,18 @@ class _HomeScreenState extends State { items = list; }); var i = 0; - Timer.periodic(const Duration(seconds: 1), (timer) { - fetchHiveInfo(list[i].author, list[i].permlink); - i += 1; - if (i == list.length) { - timer.cancel(); + while (i < list.length) { + if (mounted) { + var info = await Communicator() + .fetchHiveInfo(list[i].author, list[i].permlink); + setState(() { + payout["${list[i].author}/${list[i].permlink}"] = info; + i++; + }); + } else { + break; } - }); + } } else { showError('Status code ${response.statusCode}'); setState(() { @@ -110,37 +110,6 @@ class _HomeScreenState extends State { } } - // fetch hive info - void fetchHiveInfo(String user, String permlink) async { - var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); - request.body = json.encode({ - "id": 1, - "jsonrpc": "2.0", - "method": "bridge.get_discussion", - "params": {"author": user, "permlink": permlink, "observer": ""} - }); - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - var string = await response.stream.bytesToString(); - var result = HivePostInfo.fromJsonString(string) - .result - .resultData - .where((element) => element.permlink == permlink) - .first; - setState(() { - var upVotes = result.activeVotes.where((e) => e.rshares > 0).length; - var downVotes = result.activeVotes.where((e) => e.rshares < 0).length; - payout["$user/$permlink"] = PayoutInfo( - payout: result.payout, - downVotes: downVotes, - upVotes: upVotes, - ); - }); - } else { - print(response.reasonPhrase); - } - } - void onTap(HomeFeedItem item) { var viewModel = VideoDetailsViewModel(author: item.author, permlink: item.permlink); @@ -171,113 +140,35 @@ class _HomeScreenState extends State { }, payout); } - Future getAccessToken( - HiveUserData user, String encryptedToken) async { - const platform = MethodChannel('com.example.acela/auth'); - final String result = await platform.invokeMethod('encryptedToken', { - 'username': user.username, - 'postingKey': user.postingKey, - 'encryptedToken': encryptedToken, - }); - var memo = MemoResponse.fromJsonString(result); - if (memo.error.isNotEmpty) { - showError('Error ${memo.error}'); - throw memo.error; - } else if (memo.decrypted.isEmpty) { - throw 'Decrypted memo is empty'; - } - return memo.decrypted.replaceFirst("#", ''); - } - - Future getValidCookie(HiveUserData user) async { - var request = http.Request( - 'GET', - Uri.parse( - 'http://localhost:13050/mobile/login?username=${user.username}')); - if (user.cookie != null) { - Map map = {"cookie": user.cookie!}; - request.headers.addAll(map); - } - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - var string = await response.stream.bytesToString(); - var loginResponse = VideoUploadLoginResponse.fromJsonString(string); - if (loginResponse.error != null && loginResponse.error!.isNotEmpty) { - throw 'Error - ${loginResponse.error}'; - } else if (loginResponse.memo != null) { - var token = await getAccessToken(user, loginResponse.memo!); - var url = - 'http://localhost:13050/mobile/login?username=${user.username}&access_token=$token'; - var request = http.Request('GET', Uri.parse(url)); - http.StreamedResponse response = await request.send(); - var string = await response.stream.bytesToString(); - var tokenResponse = VideoUploadLoginResponse.fromJsonString(string); - var cookie = response.headers['set-cookie']; - if (tokenResponse.error != null && tokenResponse.error!.isNotEmpty) { - throw 'Error - ${tokenResponse.error}'; - } else if (tokenResponse.network == "hive" && - tokenResponse.banned != true && - tokenResponse.userId != null && - cookie != null && - cookie.isNotEmpty) { - const storage = FlutterSecureStorage(); - await storage.write(key: 'cookie', value: cookie); - var newData = HiveUserData( - username: user.username, - postingKey: user.postingKey, - cookie: cookie, - ); - server.updateHiveUserData(newData); - return cookie; - } else { - log('This should never happen. No error, no user info. How?'); - throw 'Something went wrong.'; - } - } else if (loginResponse.network == "hive" && - loginResponse.banned != true && - loginResponse.userId != null && - user.cookie != null) { - return user.cookie!; - } else { - log('This should never happen. No error, no memo, no user info. How?'); - throw 'Something went wrong.'; - } - } else if (response.statusCode == 500) { - var string = await response.stream.bytesToString(); - var errorResponse = VideoUploadLoginResponse.fromJsonString(string); - if (errorResponse.error != null && - errorResponse.error!.isNotEmpty && - errorResponse.error == 'session expired') { - const storage = FlutterSecureStorage(); - await storage.delete(key: 'cookie'); - var newData = HiveUserData( - username: user.username, - postingKey: user.postingKey, - cookie: null, - ); - server.updateHiveUserData(newData); - return await getValidCookie(newData); - } else { - throw 'Status code ${response.statusCode}'; - } - } else { - throw 'Status code ${response.statusCode}'; - } - } - Widget _fab(HiveUserData user) { + if (isFabLoading) { + return FloatingActionButton( + onPressed: () {}, child: const CircularProgressIndicator()); + } return FloatingActionButton( onPressed: () async { try { + setState(() { + isFabLoading = true; + }); final String result = await platform.invokeMethod('video', { 'username': user.username, 'postingKey': user.postingKey, }); log('Result is $result'); - var cookie = await getValidCookie(user); + var cookie = await Communicator().getValidCookie(user); log('Cookie is $cookie'); + var response = + await Communicator().prepareVideo(user, result, cookie); + log('Response file name is ${response.filename}'); + setState(() { + isFabLoading = false; + }); } catch (e) { showError(e.toString()); + setState(() { + isFabLoading = false; + }); } }, child: const Icon(Icons.add), diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart new file mode 100644 index 00000000..da884b0c --- /dev/null +++ b/lib/src/utils/communicator.dart @@ -0,0 +1,159 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/models/login/memo_response.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/models/video_upload/video_upload_login_response.dart'; +import 'package:acela/src/models/video_upload/video_upload_prepare_response.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:http/http.dart' as http; + +class Communicator { + static const tsServer = "http://localhost:13050"; + Future fetchHiveInfo(String user, String permlink) async { + var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + request.body = json.encode({ + "id": 1, + "jsonrpc": "2.0", + "method": "bridge.get_discussion", + "params": {"author": user, "permlink": permlink, "observer": ""} + }); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + var result = HivePostInfo.fromJsonString(string) + .result + .resultData + .where((element) => element.permlink == permlink) + .first; + var upVotes = result.activeVotes.where((e) => e.rshares > 0).length; + var downVotes = result.activeVotes.where((e) => e.rshares < 0).length; + return PayoutInfo( + payout: result.payout, + downVotes: downVotes, + upVotes: upVotes, + ); + } else { + print(response.reasonPhrase); + throw response.reasonPhrase.toString(); + } + } + + Future _getAccessToken( + HiveUserData user, String encryptedToken) async { + const platform = MethodChannel('com.example.acela/auth'); + final String result = await platform.invokeMethod('encryptedToken', { + 'username': user.username, + 'postingKey': user.postingKey, + 'encryptedToken': encryptedToken, + }); + var memo = MemoResponse.fromJsonString(result); + if (memo.error.isNotEmpty) { + throw memo.error; + } else if (memo.decrypted.isEmpty) { + throw 'Decrypted memo is empty'; + } + return memo.decrypted.replaceFirst("#", ''); + } + + Future prepareVideo( + HiveUserData user, String videoInfo, String cookie) async { + var request = http.Request('POST', + Uri.parse('${Communicator.tsServer}/mobile/api/upload/prepare')); + request.body = videoInfo; + Map map = { + "cookie": cookie, + "Content-Type": "application/json" + }; + request.headers.addAll(map); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + log('Video upload prepare response is\n$string'); + return VideoUploadPrepareResponse.fromJsonString(string); + } else { + print(response.reasonPhrase); + throw response.reasonPhrase.toString(); + } + } + + Future getValidCookie(HiveUserData user) async { + var request = http.Request( + 'GET', + Uri.parse( + '${Communicator.tsServer}/mobile/login?username=${user.username}')); + if (user.cookie != null) { + Map map = {"cookie": user.cookie!}; + request.headers.addAll(map); + } + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + var loginResponse = VideoUploadLoginResponse.fromJsonString(string); + if (loginResponse.error != null && loginResponse.error!.isNotEmpty) { + throw 'Error - ${loginResponse.error}'; + } else if (loginResponse.memo != null && loginResponse.memo!.isNotEmpty) { + var token = await _getAccessToken(user, loginResponse.memo!); + var url = + '${Communicator.tsServer}/mobile/login?username=${user.username}&access_token=$token'; + var request = http.Request('GET', Uri.parse(url)); + http.StreamedResponse response = await request.send(); + var string = await response.stream.bytesToString(); + var tokenResponse = VideoUploadLoginResponse.fromJsonString(string); + var cookie = response.headers['set-cookie']; + if (tokenResponse.error != null && tokenResponse.error!.isNotEmpty) { + throw 'Error - ${tokenResponse.error}'; + } else if (tokenResponse.network == "hive" && + tokenResponse.banned != true && + tokenResponse.userId != null && + cookie != null && + cookie.isNotEmpty) { + const storage = FlutterSecureStorage(); + await storage.write(key: 'cookie', value: cookie); + var newData = HiveUserData( + username: user.username, + postingKey: user.postingKey, + cookie: cookie, + ); + server.updateHiveUserData(newData); + return cookie; + } else { + log('This should never happen. No error, no user info. How?'); + throw 'Something went wrong.'; + } + } else if (loginResponse.network == "hive" && + loginResponse.banned != true && + loginResponse.userId != null && + user.cookie != null) { + return user.cookie!; + } else { + log('This should never happen. No error, no memo, no user info. How?'); + throw 'Something went wrong.'; + } + } else if (response.statusCode == 500) { + var string = await response.stream.bytesToString(); + var errorResponse = VideoUploadLoginResponse.fromJsonString(string); + if (errorResponse.error != null && + errorResponse.error!.isNotEmpty && + errorResponse.error == 'session expired') { + const storage = FlutterSecureStorage(); + await storage.delete(key: 'cookie'); + var newData = HiveUserData( + username: user.username, + postingKey: user.postingKey, + cookie: null, + ); + server.updateHiveUserData(newData); + return await getValidCookie(newData); + } else { + throw 'Status code ${response.statusCode}'; + } + } else { + throw 'Status code ${response.statusCode}'; + } + } +} From b389c99382436c12ca6c16ff28201ceb9a459355 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 26 May 2022 08:44:22 +0530 Subject: [PATCH 074/466] File upload work in progress. --- .flutter-plugins | 2 + .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 16 +++++ .idea/libraries/Flutter_Plugins.xml | 1 + .packages | 4 +- ios/Podfile.lock | 50 +++++++++++++++ ios/Runner/Info.plist | 11 ++++ .../video_upload/platform_video_info.dart | 35 ++++++++++ lib/src/screens/home_screen/home_screen.dart | 64 +++++++++++++++---- pubspec.lock | 14 ++++ pubspec.yaml | 1 + 11 files changed, 185 insertions(+), 15 deletions(-) create mode 100644 lib/src/models/video_upload/platform_video_info.dart diff --git a/.flutter-plugins b/.flutter-plugins index 2cdb7b9f..decd2e8e 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,6 +1,8 @@ # This is a generated file; do not edit or check into version control. +file_picker=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/ firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/ firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/ +flutter_plugin_android_lifecycle=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/ flutter_secure_storage=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/ flutter_secure_storage_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/ flutter_secure_storage_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 3c5f7948..5be3abd7 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-05-26 07:50:06.433795","version":"3.0.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-05-26 08:41:16.433118","version":"3.0.1"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index b59c9074..3bd594f9 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -240,6 +240,13 @@ + + + + + + @@ -296,6 +303,13 @@ + + + + + + @@ -928,6 +942,7 @@ + @@ -935,6 +950,7 @@ + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 8c00a45f..2f8a11c4 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -25,6 +25,7 @@ + diff --git a/.packages b/.packages index b316390e..fd38d215 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-05-24 10:33:08.585480. +# Generated by pub on 2022-05-26 08:12:21.143626. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ @@ -38,6 +38,7 @@ elliptic:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org fake_async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.3.0/lib/ ffi:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.1.2/lib/ file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib/ +file_picker:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/lib/ firebase_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/lib/ firebase_core_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_platform_interface-4.2.5/lib/ firebase_core_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/lib/ @@ -46,6 +47,7 @@ flutter:file:///Applications/flutter/flutter/packages/flutter/lib/ flutter_dotenv:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_dotenv-5.0.2/lib/ flutter_lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib/ flutter_markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_markdown-0.6.10/lib/ +flutter_plugin_android_lifecycle:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/lib/ flutter_secure_storage:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/lib/ flutter_secure_storage_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/lib/ flutter_secure_storage_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/lib/ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2c05d039..483c2087 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,4 +1,38 @@ PODS: + - DKImagePickerController/Core (4.3.3): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.3) + - DKImagePickerController/PhotoGallery (4.3.3): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.3) + - DKPhotoGallery (0.0.17): + - DKPhotoGallery/Core (= 0.0.17) + - DKPhotoGallery/Model (= 0.0.17) + - DKPhotoGallery/Preview (= 0.0.17) + - DKPhotoGallery/Resource (= 0.0.17) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.17): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.17): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter - Firebase/CoreOnly (8.15.0): - FirebaseCore (= 8.15.0) - firebase_core (1.15.0): @@ -31,8 +65,12 @@ PODS: - nanopb/decode (2.30908.0) - nanopb/encode (2.30908.0) - PromisesObjC (2.1.0) + - SDWebImage (5.12.5): + - SDWebImage/Core (= 5.12.5) + - SDWebImage/Core (5.12.5) - share_plus (0.0.1): - Flutter + - SwiftyGif (5.4.3) - url_launcher_ios (0.0.1): - Flutter - video_player_avfoundation (0.0.1): @@ -41,6 +79,7 @@ PODS: - Flutter DEPENDENCIES: + - file_picker (from `.symlinks/plugins/file_picker/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - Flutter (from `Flutter`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) @@ -52,6 +91,8 @@ DEPENDENCIES: SPEC REPOS: trunk: + - DKImagePickerController + - DKPhotoGallery - Firebase - FirebaseCore - FirebaseCoreDiagnostics @@ -60,8 +101,12 @@ SPEC REPOS: - GoogleUtilities - nanopb - PromisesObjC + - SDWebImage + - SwiftyGif EXTERNAL SOURCES: + file_picker: + :path: ".symlinks/plugins/file_picker/ios" firebase_core: :path: ".symlinks/plugins/firebase_core/ios" Flutter: @@ -78,6 +123,9 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/wakelock/ios" SPEC CHECKSUMS: + DKImagePickerController: 72fd378f244cef3d27288e0aebf217a4467e4012 + DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 + file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d firebase_core: fa19947d8db1c0a62d8872c45039b3113829cd2e FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1 @@ -89,7 +137,9 @@ SPEC CHECKSUMS: GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 PromisesObjC: 99b6f43f9e1044bd87a95a60beff28c2c44ddb72 + SDWebImage: 0905f1b7760fc8ac4198cae0036600d67478751e share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 + SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index d147d433..a8d828e5 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -52,5 +52,16 @@ UIViewControllerBasedStatusBarAppearance + UIBackgroundModes + + fetch + remote-notification + + NSAppleMusicUsageDescription + Allow access to music + UISupportsDocumentBrowser + + LSSupportsOpeningDocumentsInPlace + diff --git a/lib/src/models/video_upload/platform_video_info.dart b/lib/src/models/video_upload/platform_video_info.dart new file mode 100644 index 00000000..ecbcfbae --- /dev/null +++ b/lib/src/models/video_upload/platform_video_info.dart @@ -0,0 +1,35 @@ +import 'dart:convert'; + +import 'package:acela/src/utils/safe_convert.dart'; + +class PlatformVideoInfo { + final int? size; + final String path; + final String? oFilename; + final int? duration; + + PlatformVideoInfo({ + required this.size, + required this.path, + required this.oFilename, + required this.duration, + }); + + factory PlatformVideoInfo.fromJson(Map? json) => + PlatformVideoInfo( + size: asInt(json, 'size'), + path: asString(json, 'path'), + oFilename: asString(json, 'oFilename'), + duration: asInt(json, 'duration'), + ); + + factory PlatformVideoInfo.fromJsonString(String jsonString) => + PlatformVideoInfo.fromJson(json.decode(jsonString)); + + Map toJson() => { + 'size': size, + 'path': path, + 'oFilename': oFilename, + 'duration': duration, + }; +} diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index f7ea9065..91d77432 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -1,8 +1,10 @@ +import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/models/video_upload/platform_video_info.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; import 'package:acela/src/screens/search/search_screen.dart'; @@ -10,10 +12,13 @@ import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/communicator.dart'; +import 'package:cross_file/cross_file.dart' show XFile; +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' show get; import 'package:provider/provider.dart'; +import 'package:tus_client/tus_client.dart'; class HomeScreen extends StatefulWidget { const HomeScreen( @@ -151,19 +156,52 @@ class _HomeScreenState extends State { setState(() { isFabLoading = true; }); - final String result = await platform.invokeMethod('video', { - 'username': user.username, - 'postingKey': user.postingKey, - }); - log('Result is $result'); - var cookie = await Communicator().getValidCookie(user); - log('Cookie is $cookie'); - var response = - await Communicator().prepareVideo(user, result, cookie); - log('Response file name is ${response.filename}'); - setState(() { - isFabLoading = false; - }); + FilePickerResult? fileResult = + await FilePicker.platform.pickFiles(type: FileType.video); + + if (fileResult != null && fileResult.files.single.path != null) { + PlatformFile file = fileResult.files.single; + print(file.name); + print(file.bytes); + print(file.size); + print(file.extension); + print(file.path); + final xfile = XFile(fileResult.files.single.path!); + var fileInfoInString = json.encode(PlatformVideoInfo( + duration: 10, + oFilename: file.name, + path: file.path!, + size: file.size) + .toJson()); + var cookie = await Communicator().getValidCookie(user); + log('Cookie is $cookie'); + var response = await Communicator() + .prepareVideo(user, fileInfoInString, cookie); + log('Response file name is ${response.filename}'); + final client = TusClient( + Uri.parse("https://uploads.3speak.tv/files"), + xfile, + store: TusMemoryStore(), + ); + + // Starts the upload + await client.upload( + onComplete: () { + print("Complete!"); + // Prints the uploaded file URL + print(client.uploadUrl.toString()); + }, + onProgress: (progress) { + print("Progress: $progress"); + }, + ); + setState(() { + isFabLoading = false; + }); + } else { + // User canceled the picker + throw 'User cancelled the video picker'; + } } catch (e) { showError(e.toString()); setState(() { diff --git a/pubspec.lock b/pubspec.lock index 81a65364..5caba003 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -239,6 +239,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" + file_picker: + dependency: "direct main" + description: + name: file_picker + url: "https://pub.dartlang.org" + source: hosted + version: "4.5.1" firebase_core: dependency: "direct main" description: @@ -293,6 +300,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.10" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.6" flutter_secure_storage: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 620ad9bf..ac1d8deb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: chewie: ^1.3.0 crypto: ^3.0.2 elliptic: ^0.3.8 + file_picker: ^4.5.1 firebase_core: ^1.12.0 flutter: sdk: flutter From 827a359cab11c3decbb05866252f717809479ce2 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 7 Jun 2022 15:29:58 +0530 Subject: [PATCH 075/466] IPFS Upload work in progress. --- .flutter-plugins | 1 + .flutter-plugins-dependencies | 2 +- .idea/Android-App.iml | 9 ++++++++ .idea/libraries/Dart_Packages.xml | 16 ++++++++++++++ .idea/libraries/Flutter_Plugins.xml | 1 + .packages | 4 +++- android/app/build.gradle | 2 +- ios/Podfile.lock | 13 ++++++++++++ ios/Runner/AppDelegate.swift | 1 + ios/Runner/Info.plist | 21 ++++++++++--------- lib/src/screens/home_screen/home_screen.dart | 16 ++++++++++---- lib/src/utils/communicator.dart | 2 +- macos/Flutter/GeneratedPluginRegistrant.swift | 2 ++ pubspec.lock | 14 +++++++++++++ pubspec.yaml | 1 + 15 files changed, 87 insertions(+), 18 deletions(-) diff --git a/.flutter-plugins b/.flutter-plugins index decd2e8e..0814aaa6 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,4 +1,5 @@ # This is a generated file; do not edit or check into version control. +ffmpeg_kit_flutter=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/ file_picker=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/ firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/ firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 5be3abd7..649a61a2 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-05-26 08:41:16.433118","version":"3.0.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-06-07 15:28:21.437064","version":"3.0.1"} \ No newline at end of file diff --git a/.idea/Android-App.iml b/.idea/Android-App.iml index dafcc4cf..0f347b5b 100644 --- a/.idea/Android-App.iml +++ b/.idea/Android-App.iml @@ -47,6 +47,15 @@ + + + + + + + + + diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 3bd594f9..6b10da4d 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -233,6 +233,20 @@ + + + + + + + + + + + + @@ -941,6 +955,8 @@ + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 2f8a11c4..c3e9d453 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -26,6 +26,7 @@ + diff --git a/.packages b/.packages index fd38d215..61e5dbf4 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-05-26 08:12:21.143626. +# Generated by pub on 2022-05-28 08:35:16.284736. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ @@ -37,6 +37,8 @@ dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.o elliptic:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/elliptic-0.3.8/lib/ fake_async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.3.0/lib/ ffi:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.1.2/lib/ +ffmpeg_kit_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/lib/ +ffmpeg_kit_flutter_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter_platform_interface-0.2.1/lib/ file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib/ file_picker:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/lib/ firebase_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/lib/ diff --git a/android/app/build.gradle b/android/app/build.gradle index a23c309f..ca43bad7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -44,7 +44,7 @@ android { defaultConfig { applicationId "com.example.acela" - minSdkVersion 19 + minSdkVersion 24 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 483c2087..963a2750 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -30,6 +30,13 @@ PODS: - DKPhotoGallery/Resource (0.0.17): - SDWebImage - SwiftyGif + - ffmpeg-kit-ios-https (4.5.1) + - ffmpeg_kit_flutter (4.5.1): + - ffmpeg_kit_flutter/https (= 4.5.1) + - Flutter + - ffmpeg_kit_flutter/https (4.5.1): + - ffmpeg-kit-ios-https (= 4.5.1) + - Flutter - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter @@ -79,6 +86,7 @@ PODS: - Flutter DEPENDENCIES: + - ffmpeg_kit_flutter (from `.symlinks/plugins/ffmpeg_kit_flutter/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - Flutter (from `Flutter`) @@ -93,6 +101,7 @@ SPEC REPOS: trunk: - DKImagePickerController - DKPhotoGallery + - ffmpeg-kit-ios-https - Firebase - FirebaseCore - FirebaseCoreDiagnostics @@ -105,6 +114,8 @@ SPEC REPOS: - SwiftyGif EXTERNAL SOURCES: + ffmpeg_kit_flutter: + :path: ".symlinks/plugins/ffmpeg_kit_flutter/ios" file_picker: :path: ".symlinks/plugins/file_picker/ios" firebase_core: @@ -125,6 +136,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: DKImagePickerController: 72fd378f244cef3d27288e0aebf217a4467e4012 DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 + ffmpeg-kit-ios-https: cec24d405b511e4f274980d8a9c751d384f89558 + ffmpeg_kit_flutter: e2f0bd6b75e361faeee3b34c70650d3ec6ec35d0 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d firebase_core: fa19947d8db1c0a62d8872c45039b3113829cd2e diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index ad96e8cd..18e60fca 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,5 +1,6 @@ import UIKit import Flutter +import AVKit @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index a8d828e5..0616e779 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -26,13 +26,23 @@ $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS + LSSupportsOpeningDocumentsInPlace + NSAppTransportSecurity NSAllowsArbitraryLoads + NSAppleMusicUsageDescription + Allow access to music NSPhotoLibraryUsageDescription Allow access to videos + UIBackgroundModes + + audio + fetch + remote-notification + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -50,18 +60,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - - UIBackgroundModes - - fetch - remote-notification - - NSAppleMusicUsageDescription - Allow access to music UISupportsDocumentBrowser - LSSupportsOpeningDocumentsInPlace + UIViewControllerBasedStatusBarAppearance diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 91d77432..3d5d88f7 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -13,6 +13,8 @@ import 'package:acela/src/screens/video_details_screen/video_details_screen.dart import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:cross_file/cross_file.dart' show XFile; +import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; +import 'package:ffmpeg_kit_flutter/media_information_session.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -166,12 +168,18 @@ class _HomeScreenState extends State { print(file.size); print(file.extension); print(file.path); + MediaInformationSession session = + await FFprobeKit.getMediaInformation(file.path!); + var info = session.getMediaInformation(); + var duration = + (double.tryParse(info?.getDuration() ?? "0.0") ?? 0.0).toInt(); + log('Video duration is $duration'); final xfile = XFile(fileResult.files.single.path!); var fileInfoInString = json.encode(PlatformVideoInfo( - duration: 10, - oFilename: file.name, - path: file.path!, - size: file.size) + duration: int.tryParse(info?.getDuration() ?? "0") ?? 0, + oFilename: xfile.name, + path: xfile.path, + size: int.tryParse(info?.getSize() ?? "0") ?? 0) .toJson()); var cookie = await Communicator().getValidCookie(user); log('Cookie is $cookie'); diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index da884b0c..0c099341 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -13,7 +13,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:http/http.dart' as http; class Communicator { - static const tsServer = "http://localhost:13050"; + static const tsServer = "http://10.0.2.2:13050"; Future fetchHiveInfo(String user, String permlink) async { var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); request.body = json.encode({ diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index fa27097b..2f2cf3cc 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import ffmpeg_kit_flutter import firebase_core import flutter_secure_storage_macos import share_plus_macos @@ -12,6 +13,7 @@ import url_launcher_macos import wakelock_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FlutterSecureStorageMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageMacosPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 5caba003..2dc59817 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -232,6 +232,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.2" + ffmpeg_kit_flutter: + dependency: "direct main" + description: + name: ffmpeg_kit_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "4.5.1" + ffmpeg_kit_flutter_platform_interface: + dependency: transitive + description: + name: ffmpeg_kit_flutter_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" file: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ac1d8deb..0ecc8985 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: chewie: ^1.3.0 crypto: ^3.0.2 elliptic: ^0.3.8 + ffmpeg_kit_flutter: ^4.5.1 file_picker: ^4.5.1 firebase_core: ^1.12.0 flutter: From d114a59c6f903bd6a65f800fa90718325aed1d21 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 7 Jun 2022 16:03:17 +0530 Subject: [PATCH 076/466] picture in picture for iOS --- .flutter-plugins | 7 + .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 132 +++++++++++++++++- .idea/libraries/Flutter_Plugins.xml | 7 + .packages | 20 ++- ios/Podfile.lock | 41 ++++++ .../video_details_screen.dart | 35 ++--- lib/src/widgets/video_player.dart | 80 +++++++---- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 118 +++++++++++++++- pubspec.yaml | 1 + 11 files changed, 393 insertions(+), 52 deletions(-) diff --git a/.flutter-plugins b/.flutter-plugins index 0814aaa6..76cd5bf4 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,4 +1,5 @@ # This is a generated file; do not edit or check into version control. +better_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/ ffmpeg_kit_flutter=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/ file_picker=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/ firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/ @@ -9,6 +10,12 @@ flutter_secure_storage_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub flutter_secure_storage_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/ flutter_secure_storage_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/ flutter_secure_storage_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/ +path_provider=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.11/ +path_provider_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/ +path_provider_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/ +path_provider_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/ +path_provider_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/ +path_provider_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/ share_plus=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/ share_plus_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/ share_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 649a61a2..ce8d2650 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-06-07 15:28:21.437064","version":"3.0.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-06-07 16:00:33.195296","version":"3.0.1"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 6b10da4d..525f11ff 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -44,6 +44,13 @@ + + + + + + @@ -201,7 +208,7 @@ - @@ -380,6 +387,13 @@ + + + + + + @@ -394,6 +408,13 @@ + + + + + + @@ -548,6 +569,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -562,6 +646,13 @@ + + + + + + @@ -856,6 +947,13 @@ + + + + + + @@ -912,6 +1010,20 @@ + + + + + + + + + + + + @@ -928,6 +1040,7 @@ + @@ -950,7 +1063,7 @@ - + @@ -973,8 +1086,10 @@ + + @@ -997,8 +1112,18 @@ + + + + + + + + + + @@ -1040,6 +1165,7 @@ + @@ -1048,6 +1174,8 @@ + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index c3e9d453..a2196ef2 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -27,6 +27,13 @@ + + + + + + + diff --git a/.packages b/.packages index 61e5dbf4..d6d39f82 100644 --- a/.packages +++ b/.packages @@ -3,13 +3,14 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-05-28 08:35:16.284736. +# Generated by pub on 2022-06-07 15:34:22.884653. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ base_x:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/base_x-2.0.0/lib/ +better_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/lib/ boolean_selector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/ bs58:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/bs58-1.0.2/lib/ bs58check:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/bs58check-1.0.2/lib/ @@ -32,7 +33,7 @@ convert:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ cross_file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cross_file-0.3.3/lib/ crypto:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.2/lib/ csslib:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.17.1/lib/ -cupertino_icons:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.4/lib/ +cupertino_icons:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.5/lib/ dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.3/lib/ elliptic:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/elliptic-0.3.8/lib/ fake_async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.3.0/lib/ @@ -58,8 +59,10 @@ flutter_secure_storage_web:file:///Applications/flutter/flutter/.pub-cache/hoste flutter_secure_storage_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/lib/ flutter_test:file:///Applications/flutter/flutter/packages/flutter_test/lib/ flutter_web_plugins:file:///Applications/flutter/flutter/packages/flutter_web_plugins/lib/ +flutter_widget_from_html_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_widget_from_html_core-0.8.5+3/lib/ font_awesome_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/font_awesome_flutter-10.1.0/lib/ frontend_server_client:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/frontend_server_client-2.1.2/lib/ +fwfh_text_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fwfh_text_style-2.7.3+2/lib/ glob:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/glob-2.0.2/lib/ graphs:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/graphs-2.1.0/lib/ hex:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/hex-0.2.0/lib/ @@ -82,8 +85,18 @@ mime:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/mim nested:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/nested-1.0.0/lib/ package_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_config-2.0.2/lib/ path:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.1/lib/ +path_provider:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.11/lib/ +path_provider_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/lib/ +path_provider_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/lib/ +path_provider_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/lib/ +path_provider_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/lib/ +path_provider_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_platform_interface-2.0.4/lib/ +path_provider_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/lib/ +petitparser:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/petitparser-5.0.0/lib/ +platform:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/platform-3.1.0/lib/ plugin_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2/lib/ pool:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pool-1.5.0/lib/ +process:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/process-4.2.4/lib/ provider:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/provider-6.0.2/lib/ pub_semver:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pub_semver-2.1.1/lib/ pubspec_parse:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pubspec_parse-1.2.0/lib/ @@ -126,6 +139,7 @@ video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.2/lib/ video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/lib/ video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/lib/ +visibility_detector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/visibility_detector-0.3.3/lib/ wakelock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/lib/ wakelock_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/lib/ wakelock_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_platform_interface-0.3.0/lib/ @@ -134,5 +148,7 @@ wakelock_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dart watcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/watcher-1.0.1/lib/ web_socket_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.2.0/lib/ win32:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/win32-2.5.2/lib/ +xdg_directories:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/xdg_directories-0.2.0+1/lib/ +xml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/xml-6.1.0/lib/ yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/yaml-3.1.0/lib/ acela:lib/ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 963a2750..6a00e9a7 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,4 +1,11 @@ PODS: + - better_player (0.0.1): + - Cache (~> 6.0.0) + - Flutter + - GCDWebServer + - HLSCachingReverseProxyServer + - PINCache + - Cache (6.0.0) - DKImagePickerController/Core (4.3.3): - DKImagePickerController/ImageDataManager - DKImagePickerController/Resource @@ -58,6 +65,9 @@ PODS: - flutter_secure_storage (3.3.1): - Flutter - FYVideoCompressor (0.0.3) + - GCDWebServer (3.5.4): + - GCDWebServer/Core (= 3.5.4) + - GCDWebServer/Core (3.5.4) - GoogleDataTransport (9.1.4): - GoogleUtilities/Environment (~> 7.7) - nanopb (< 2.30910.0, >= 2.30908.0) @@ -66,11 +76,24 @@ PODS: - PromisesObjC (< 3.0, >= 1.2) - GoogleUtilities/Logger (7.7.0): - GoogleUtilities/Environment + - HLSCachingReverseProxyServer (0.1.0): + - GCDWebServer (~> 3.5) + - PINCache (>= 3.0.1-beta.3) - nanopb (2.30908.0): - nanopb/decode (= 2.30908.0) - nanopb/encode (= 2.30908.0) - nanopb/decode (2.30908.0) - nanopb/encode (2.30908.0) + - path_provider_ios (0.0.1): + - Flutter + - PINCache (3.0.3): + - PINCache/Arc-exception-safe (= 3.0.3) + - PINCache/Core (= 3.0.3) + - PINCache/Arc-exception-safe (3.0.3): + - PINCache/Core + - PINCache/Core (3.0.3): + - PINOperation (~> 1.2.1) + - PINOperation (1.2.1) - PromisesObjC (2.1.0) - SDWebImage (5.12.5): - SDWebImage/Core (= 5.12.5) @@ -86,12 +109,14 @@ PODS: - Flutter DEPENDENCIES: + - better_player (from `.symlinks/plugins/better_player/ios`) - ffmpeg_kit_flutter (from `.symlinks/plugins/ffmpeg_kit_flutter/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - Flutter (from `Flutter`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - FYVideoCompressor + - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) @@ -99,6 +124,7 @@ DEPENDENCIES: SPEC REPOS: trunk: + - Cache - DKImagePickerController - DKPhotoGallery - ffmpeg-kit-ios-https @@ -106,14 +132,20 @@ SPEC REPOS: - FirebaseCore - FirebaseCoreDiagnostics - FYVideoCompressor + - GCDWebServer - GoogleDataTransport - GoogleUtilities + - HLSCachingReverseProxyServer - nanopb + - PINCache + - PINOperation - PromisesObjC - SDWebImage - SwiftyGif EXTERNAL SOURCES: + better_player: + :path: ".symlinks/plugins/better_player/ios" ffmpeg_kit_flutter: :path: ".symlinks/plugins/ffmpeg_kit_flutter/ios" file_picker: @@ -124,6 +156,8 @@ EXTERNAL SOURCES: :path: Flutter flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" + path_provider_ios: + :path: ".symlinks/plugins/path_provider_ios/ios" share_plus: :path: ".symlinks/plugins/share_plus/ios" url_launcher_ios: @@ -134,6 +168,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/wakelock/ios" SPEC CHECKSUMS: + better_player: 2406bfe8175203c7a46fa15f9d778d73b12e1646 + Cache: 4ca7e00363fca5455f26534e5607634c820ffc2d DKImagePickerController: 72fd378f244cef3d27288e0aebf217a4467e4012 DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 ffmpeg-kit-ios-https: cec24d405b511e4f274980d8a9c751d384f89558 @@ -146,9 +182,14 @@ SPEC CHECKSUMS: Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec FYVideoCompressor: 6d745d0b28432c6abacb234c3c1263755248136b + GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4 GoogleDataTransport: 5fffe35792f8b96ec8d6775f5eccd83c998d5a3b GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 + HLSCachingReverseProxyServer: 59935e1e0244ad7f3375d75b5ef46e8eb26ab181 nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 + path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 + PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 + PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20 PromisesObjC: 99b6f43f9e1044bd87a95a60beff28c2c44ddb72 SDWebImage: 0905f1b7760fc8ac4198cae0036600d67478751e share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index cc24ed9c..a54e8265 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -42,22 +42,22 @@ class _VideoDetailsScreenState extends State { @override void initState() { super.initState(); - widget.vm.getRecommendedVideos().then((value) { - setState(() { - recommendations = value; - }); - var i = 0; - Timer.periodic(const Duration(seconds: 1), (timer) { - fetchHiveInfo(value[i].owner, value[i].mediaid); - i += 1; - if (i == value.length) { - timer.cancel(); - } - }); - }); - _loadComments = - widget.vm.loadFirstSetOfComments(widget.vm.author, widget.vm.permlink); - fetchHiveInfoForThisVideo(); + // widget.vm.getRecommendedVideos().then((value) { + // setState(() { + // recommendations = value; + // }); + // var i = 0; + // Timer.periodic(const Duration(seconds: 1), (timer) { + // fetchHiveInfo(value[i].owner, value[i].mediaid); + // i += 1; + // if (i == value.length) { + // timer.cancel(); + // } + // }); + // }); + // _loadComments = + // widget.vm.loadFirstSetOfComments(widget.vm.author, widget.vm.permlink); + // fetchHiveInfoForThisVideo(); } void onUserTap() { @@ -415,7 +415,8 @@ class _VideoDetailsScreenState extends State { String text = 'Something went wrong while loading video information - ${snapshot.error?.toString() ?? ""}'; return container(widget.vm.author, Text(text)); - } else if (snapshot.hasData) { + } else if (snapshot.hasData && + snapshot.connectionState == ConnectionState.done) { var data = snapshot.data as VideoDetails?; if (data != null) { return Scaffold( diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index 8be040f6..5f001617 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -1,12 +1,11 @@ -import 'package:acela/src/widgets/loading_screen.dart'; +// import 'package:video_player/video_player.dart'; +// import 'package:chewie/chewie.dart'; + +import 'package:better_player/better_player.dart'; import 'package:flutter/material.dart'; -import 'package:video_player/video_player.dart'; -import 'package:chewie/chewie.dart'; class SPKVideoPlayer extends StatefulWidget { - const SPKVideoPlayer( - {Key? key, required this.playUrl}) - : super(key: key); + const SPKVideoPlayer({Key? key, required this.playUrl}) : super(key: key); final String playUrl; @override @@ -14,35 +13,62 @@ class SPKVideoPlayer extends StatefulWidget { } class _SPKVideoPlayerState extends State { - late VideoPlayerController videoPlayerController; - ChewieController? chewieController; + // late VideoPlayerController videoPlayerController; + // ChewieController? chewieController; + late BetterPlayerController _betterPlayerController; + GlobalKey _betterPlayerKey = GlobalKey(); - @override - void dispose() { - super.dispose(); - videoPlayerController.dispose(); - } + // @override + // void dispose() { + // super.dispose(); + // videoPlayerController.dispose(); + // } + + // @override + // void initState() { + // videoPlayerController = VideoPlayerController.network(widget.playUrl, + // videoPlayerOptions: VideoPlayerOptions(allowBackgroundPlayback: true)) + // ..initialize().then((_) { + // setState(() { + // chewieController = ChewieController( + // videoPlayerController: videoPlayerController, + // autoPlay: true, + // looping: false, + // ); + // }); + // }); + // super.initState(); + // } + + // @override + // Widget build(BuildContext context) { + // return chewieController == null + // ? const LoadingScreen() + // : Chewie(controller: chewieController!); + // } @override void initState() { - videoPlayerController = VideoPlayerController.network(widget.playUrl, - videoPlayerOptions: VideoPlayerOptions(allowBackgroundPlayback: true)) - ..initialize().then((_) { - setState(() { - chewieController = ChewieController( - videoPlayerController: videoPlayerController, - autoPlay: true, - looping: false, - ); - }); - }); + BetterPlayerConfiguration betterPlayerConfiguration = + BetterPlayerConfiguration( + aspectRatio: 16 / 9, + fit: BoxFit.contain, + ); + BetterPlayerDataSource dataSource = BetterPlayerDataSource( + BetterPlayerDataSourceType.network, + widget.playUrl, + ); + _betterPlayerController = BetterPlayerController(betterPlayerConfiguration); + _betterPlayerController.setupDataSource(dataSource); + _betterPlayerController.setBetterPlayerGlobalKey(_betterPlayerKey); super.initState(); } @override Widget build(BuildContext context) { - return chewieController == null - ? const LoadingScreen() - : Chewie(controller: chewieController!); + return BetterPlayer( + controller: _betterPlayerController, + key: _betterPlayerKey, + ); } } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 2f2cf3cc..2341897a 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,6 +8,7 @@ import Foundation import ffmpeg_kit_flutter import firebase_core import flutter_secure_storage_macos +import path_provider_macos import share_plus_macos import url_launcher_macos import wakelock_macos @@ -16,6 +17,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FlutterSecureStorageMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageMacosPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 2dc59817..ba13dd87 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -43,6 +43,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + better_player: + dependency: "direct main" + description: + name: better_player + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.83" boolean_selector: dependency: transitive description: @@ -203,7 +210,7 @@ packages: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" dart_style: dependency: transitive description: @@ -373,6 +380,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_widget_from_html_core: + dependency: transitive + description: + name: flutter_widget_from_html_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.5+3" font_awesome_flutter: dependency: "direct main" description: @@ -387,6 +401,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + fwfh_text_style: + dependency: transitive + description: + name: fwfh_text_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.7.3+2" glob: dependency: transitive description: @@ -541,6 +562,69 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.1" + path_provider: + dependency: transitive + description: + name: path_provider + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.14" + path_provider_ios: + dependency: transitive + description: + name: path_provider_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.9" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.7" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.6" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.7" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.0" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" plugin_platform_interface: dependency: transitive description: @@ -555,6 +639,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.5.0" + process: + dependency: transitive + description: + name: process + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.4" provider: dependency: "direct main" description: @@ -847,6 +938,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.11+4" + visibility_detector: + dependency: transitive + description: + name: visibility_detector + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.3" wakelock: dependency: transitive description: @@ -903,6 +1001,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.5.2" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0+1" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.0" yaml: dependency: transitive description: @@ -911,5 +1023,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.17.0-0 <3.0.0" - flutter: ">=2.10.0" + dart: ">=2.17.0 <3.0.0" + flutter: ">=2.12.0" diff --git a/pubspec.yaml b/pubspec.yaml index 0ecc8985..b1234a3c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,6 +28,7 @@ environment: # versions available, run `flutter pub outdated`. dependencies: adaptive_action_sheet: ^2.0.1 + better_player: ^0.0.83 bs58: ^1.0.2 bs58check: ^1.0.2 chewie: ^1.3.0 From ae7a3ff1a66f1d6f7bbfe1cb2b63dcef9c1c5446 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 7 Jun 2022 17:15:09 +0530 Subject: [PATCH 077/466] picture in picture support for android. --- .flutter-plugins-dependencies | 2 +- android/.idea/compiler.xml | 6 ------ android/.idea/gradle.xml | 13 ------------- android/.idea/misc.xml | 2 +- android/.idea/modules.xml | 7 ------- android/.idea/modules/android.iml | 14 +++++++------- android/app/src/main/AndroidManifest.xml | 1 + 7 files changed, 10 insertions(+), 35 deletions(-) delete mode 100644 android/.idea/compiler.xml diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index ce8d2650..0ba6755b 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-06-07 16:00:33.195296","version":"3.0.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-06-07 17:03:25.934871","version":"3.0.1"} \ No newline at end of file diff --git a/android/.idea/compiler.xml b/android/.idea/compiler.xml deleted file mode 100644 index fb7f4a8a..00000000 --- a/android/.idea/compiler.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml index 729b70ae..b898c0af 100644 --- a/android/.idea/gradle.xml +++ b/android/.idea/gradle.xml @@ -1,24 +1,11 @@ - diff --git a/android/.idea/misc.xml b/android/.idea/misc.xml index 2a4d5b52..46fefaa0 100644 --- a/android/.idea/misc.xml +++ b/android/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/android/.idea/modules.xml b/android/.idea/modules.xml index 341e37b4..bf609e00 100644 --- a/android/.idea/modules.xml +++ b/android/.idea/modules.xml @@ -3,13 +3,6 @@ - - - - - - - \ No newline at end of file diff --git a/android/.idea/modules/android.iml b/android/.idea/modules/android.iml index 4e86d157..5b2d4071 100644 --- a/android/.idea/modules/android.iml +++ b/android/.idea/modules/android.iml @@ -1,17 +1,17 @@ - + - + - - + - - - + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index ca3fe0cc..3d38ec6b 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ android:icon="@mipmap/ic_launcher"> Date: Fri, 10 Jun 2022 17:26:13 +0530 Subject: [PATCH 078/466] Video Details - Future load payout info for video. --- .flutter-plugins-dependencies | 2 +- .idea/Android-App.iml | 12 ++ android/.idea/gradle.xml | 1 + lib/src/screens/home_screen/home_screen.dart | 2 +- .../video_details_screen.dart | 131 ++++++++++-------- lib/src/utils/communicator.dart | 3 +- 6 files changed, 90 insertions(+), 61 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 0ba6755b..d0c1295c 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-06-07 17:03:25.934871","version":"3.0.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-06-10 17:21:40.433649","version":"3.0.1"} \ No newline at end of file diff --git a/.idea/Android-App.iml b/.idea/Android-App.iml index 0f347b5b..2b683642 100644 --- a/.idea/Android-App.iml +++ b/.idea/Android-App.iml @@ -56,6 +56,18 @@ + + + + + + + + + + + + diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml index b898c0af..f22a5399 100644 --- a/android/.idea/gradle.xml +++ b/android/.idea/gradle.xml @@ -1,5 +1,6 @@ + + + + + + + @@ -1189,6 +1196,7 @@ + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index e85bacff..037d0155 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -36,6 +36,7 @@ + diff --git a/.packages b/.packages index 242eb3c3..61922157 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-06-25 18:09:41.284728. +# Generated by pub on 2022-07-03 20:00:47.065585. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ @@ -142,6 +142,7 @@ video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.2/lib/ video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/lib/ video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/lib/ +video_thumbnail:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/lib/ visibility_detector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/visibility_detector-0.3.3/lib/ wakelock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/lib/ wakelock_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/lib/ diff --git a/android/app/src/main/assets/index.html b/android/app/src/main/assets/index.html index 32a8eb45..260a6351 100644 --- a/android/app/src/main/assets/index.html +++ b/android/app/src/main/assets/index.html @@ -79,11 +79,21 @@ }); } + function renderTemplate(video) { + const PostTemplate = `


[![](@@@thumbnail@@@)](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)

[Watch on 3Speak](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)



---

@@@description@@@

---

[3Speak](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)
`; + return PostTemplate.replace(/@@@thumbnail@@@/g, video.baseThumbUrl) + .replace(/@@@author@@@/g, video.owner) + .replace(/@@@permlink@@@/g, video.permlink) + .replace(/@@@description@@@/g, video.description); + } + function postVideo(data, postingKey) { console.log(`Response received from server: ${data}`); const result = JSON.parse(data).data; const json_metadata = JSON.stringify(result.json_metadata); - const comment = { ...result.comment, json_metadata: json_metadata }; + const video = result.videoBody; + let comment = { ...result.comment, json_metadata: json_metadata }; + comment.body = renderTemplate(video); const newExtensions = result.extensions.sort((a, b) => { let fa = a.account.toLowerCase(), fb = b.account.toLowerCase(); @@ -102,7 +112,7 @@ ["comment_options", comment_options], ["custom_json", custom_json], ]; - console.log(`ops is ${ops}`); + console.log(`ops is ${ops}`); async function tryPublish(operations, key) { try { return hive.broadcast.sendAsync({ operations }, { posting: key }); diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 902f7234..3e670098 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -113,6 +113,15 @@ PODS: - HLSCachingReverseProxyServer (0.1.0): - GCDWebServer (~> 3.5) - PINCache (>= 3.0.1-beta.3) + - libwebp (1.2.1): + - libwebp/demux (= 1.2.1) + - libwebp/mux (= 1.2.1) + - libwebp/webp (= 1.2.1) + - libwebp/demux (1.2.1): + - libwebp/webp + - libwebp/mux (1.2.1): + - libwebp/demux + - libwebp/webp (1.2.1) - nanopb (2.30908.0): - nanopb/decode (= 2.30908.0) - nanopb/encode (= 2.30908.0) @@ -139,6 +148,9 @@ PODS: - Flutter - video_player_avfoundation (0.0.1): - Flutter + - video_thumbnail (0.0.1): + - Flutter + - libwebp - wakelock (0.0.1): - Flutter @@ -155,6 +167,7 @@ DEPENDENCIES: - share_plus (from `.symlinks/plugins/share_plus/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) + - video_thumbnail (from `.symlinks/plugins/video_thumbnail/ios`) - wakelock (from `.symlinks/plugins/wakelock/ios`) SPEC REPOS: @@ -173,6 +186,7 @@ SPEC REPOS: - GoogleDataTransport - GoogleUtilities - HLSCachingReverseProxyServer + - libwebp - nanopb - PINCache - PINOperation @@ -203,6 +217,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/url_launcher_ios/ios" video_player_avfoundation: :path: ".symlinks/plugins/video_player_avfoundation/ios" + video_thumbnail: + :path: ".symlinks/plugins/video_thumbnail/ios" wakelock: :path: ".symlinks/plugins/wakelock/ios" @@ -228,6 +244,7 @@ SPEC CHECKSUMS: GoogleDataTransport: 5fffe35792f8b96ec8d6775f5eccd83c998d5a3b GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 HLSCachingReverseProxyServer: 59935e1e0244ad7f3375d75b5ef46e8eb26ab181 + libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 @@ -238,6 +255,7 @@ SPEC CHECKSUMS: SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff + video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1 wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f PODFILE CHECKSUM: c47b194cb97680e602c9d704f278cff245139eb7 diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index 9ddd32b7..9cb2b878 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -16,6 +16,7 @@ class AcelaWebViewController: UIViewController { var didFinish = false var postingKeyValidationHandler: ((String) -> Void)? var decryptTokenHandler: ((String) -> Void)? + var postVideoHandler: ((String) -> Void)? override func viewDidLoad() { super.viewDidLoad() @@ -36,7 +37,7 @@ class AcelaWebViewController: UIViewController { ) { postingKeyValidationHandler = handler OperationQueue.main.addOperation { - self.webView?.evaluateJavaScript("validateHiveKey('\(username)', '\(postingKey)')") + self.webView?.evaluateJavaScript("validateHiveKey('\(username)', '\(postingKey)');") } } @@ -48,7 +49,18 @@ class AcelaWebViewController: UIViewController { ) { decryptTokenHandler = handler OperationQueue.main.addOperation { - self.webView?.evaluateJavaScript("decryptMemo('\(username)', '\(postingKey)', '\(encryptedMemo)')") + self.webView?.evaluateJavaScript("decryptMemo('\(username)', '\(postingKey)', '\(encryptedMemo)');") + } + } + + func postVideo( + data: String, + postingKey: String, + handler: @escaping (String) -> Void + ) { + postVideoHandler = handler + OperationQueue.main.addOperation { + self.webView?.evaluateJavaScript("postVideo('\(data)', '\(postingKey)');") } } } @@ -72,7 +84,6 @@ extension AcelaWebViewController: WKScriptMessageHandler { guard let isValid = dict["valid"] as? Bool, let accountName = dict["accountName"] as? String, - let postingKey = dict["postingKey"] as? String, let error = dict["error"] as? String, let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) else { return } @@ -91,6 +102,15 @@ extension AcelaWebViewController: WKScriptMessageHandler { debugPrint("Error is \(error)") debugPrint("decrypted is \(decrypted)") decryptTokenHandler?(response) + case "postVideo": + guard + let isValid = dict["valid"] as? Bool, + let error = dict["error"] as? String, + let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) + else { return } + debugPrint("Is it valid? \(isValid ? "TRUE" : "FALSE")") + debugPrint("Error is \(error)") + postingKeyValidationHandler?(response) default: debugPrint("Do nothing here.") } } diff --git a/ios/Runner/Bridges/Auth/AuthBridge.swift b/ios/Runner/Bridges/Auth/AuthBridge.swift index c16a9c63..00a44bdb 100644 --- a/ios/Runner/Bridges/Auth/AuthBridge.swift +++ b/ios/Runner/Bridges/Auth/AuthBridge.swift @@ -44,6 +44,15 @@ class AuthBridge { return } self?.decryptMemo(username: username, postingKey: password, encryptedMemo: encryptedToken, result: result) + case "postVideo": + guard + let arguments = call.arguments as? NSDictionary, + let data = arguments ["data"] as? String, + let password = arguments["postingKey"] as? String + else { + result(FlutterMethodNotImplemented) + return + } default: debugPrint("do nothing") } }) @@ -77,4 +86,16 @@ class AuthBridge { result(response) } } + + private func postVideo(data: String, postingKey: String, result: @escaping FlutterResult) { + guard let acela = acela else { + result(FlutterError(code: "ERROR", + message: "Error Uploading video from iOS native bridge", + details: nil)) + return + } + acela.postVideo(data: data, postingKey: postingKey) { response in + result(response) + } + } } diff --git a/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift b/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift index 1a951fe2..8b939ed9 100644 --- a/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift +++ b/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift @@ -9,21 +9,17 @@ import Foundation struct ValidateHiveKeyResponse: Codable { let valid: Bool - let accountName: String - let postingKey: String + let accountName: String? let error: String static func jsonStringFrom(dict: [String: AnyObject]) -> String? { guard let isValid = dict["valid"] as? Bool, - let accountName = dict["accountName"] as? String, - let postingKey = dict["postingKey"] as? String, let error = dict["error"] as? String else { return nil } let response = ValidateHiveKeyResponse( valid: isValid, - accountName: accountName, - postingKey: postingKey, + accountName: dict["accountName"] as? String, error: error ) guard let data = try? JSONEncoder().encode(response) else { return nil } diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index ee17a755..4e5095b5 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -27,7 +27,6 @@ type: "validateHiveKey", valid: Valid, accountName: accountName, - postingKey: postingKey, error: "", }); }) @@ -37,11 +36,11 @@ type: "validateHiveKey", valid: false, accountName: accountName, - postingKey: postingKey, error: err.message, }); }); } + function decryptMemo(accountName, postingKey, encrypted) { console.log("In here before async"); hive.api @@ -71,6 +70,69 @@ }); }); } + + function renderTemplate(video) { + const PostTemplate = `


[![](@@@thumbnail@@@)](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)

[Watch on 3Speak](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)



---

@@@description@@@

---

[3Speak](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)
`; + return PostTemplate.replace(/@@@thumbnail@@@/g, video.baseThumbUrl) + .replace(/@@@author@@@/g, video.owner) + .replace(/@@@permlink@@@/g, video.permlink) + .replace(/@@@description@@@/g, video.description); + } + + function postVideo(data, postingKey) { + console.log(`Response received from server: ${data}`); + const result = JSON.parse(data).data; + const json_metadata = JSON.stringify(result.json_metadata); + const video = result.videoBody; + let comment = { ...result.comment, json_metadata: json_metadata }; + comment.body = renderTemplate(video); + const newExtensions = result.extensions.sort((a, b) => { + let fa = a.account.toLowerCase(), + fb = b.account.toLowerCase(); + if (fa < fb) return -1; + if (fa > fb) return 1; + return 0; + }); + const comment_options = { + ...result.comment_options, + extensions: [[0, { beneficiaries: newExtensions }]], + }; + const json = JSON.stringify(result.custom_json.json); + const custom_json = { ...result.custom_json, json: json }; + const ops = [ + ["comment", comment], + ["comment_options", comment_options], + ["custom_json", custom_json], + ]; + console.log(`ops is ${ops}`); + async function tryPublish(operations, key) { + try { + return hive.broadcast.sendAsync({ operations }, { posting: key }); + } catch (e) { + return e; + } + } + tryPublish(ops, postingKey) + .then((result) => { + var newResult = { + type: "postVideo", + valid: true, + error: JSON.stringify(result), + }; + window.webkit.messageHandlers.acela.postMessage(result); + // Android.postMessage(JSON.stringify(newResult)); + }) + .catch((error) => { + console.error(error); + var result = { + type: "postVideo", + valid: false, + error: error.message, + }; + window.webkit.messageHandlers.acela.postMessage(result); + // Android.postMessage(JSON.stringify(result)); + }); + } diff --git a/lib/src/models/login/login_bridge_response.dart b/lib/src/models/login/login_bridge_response.dart index 0656ae4f..213d17e8 100644 --- a/lib/src/models/login/login_bridge_response.dart +++ b/lib/src/models/login/login_bridge_response.dart @@ -4,7 +4,7 @@ import 'package:acela/src/utils/safe_convert.dart'; class LoginBridgeResponse { final bool valid; - final String accountName; + final String? accountName; final String error; LoginBridgeResponse({ diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 7f55572a..43cad90f 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -192,12 +192,13 @@ class _HomeScreenState extends State { var response = await Communicator() .prepareVideo(user, fileInfoInString, cookie); log('Response file name is ${response.filename}'); - var screen = UploadScreen(videoId: response.video.id, xFile: xfile); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); setState(() { - isLoading = false; + isFabLoading = false; log('Loading is set to false - $isLoading'); + var screen = + UploadScreen(videoId: response.video.id, xFile: xfile); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); }); } else { throw 'User cancelled the video picker'; diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 95cd0344..c47c5077 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -123,7 +123,7 @@ class _LoginScreenState extends State { IconButton( onPressed: () { showMessage( - 'Concerned about security? Rest assured.\nYour posting key never leaves this app.\nIt is securely stored on your device ONLY.\nNo one, including us, will ever have it.'); + 'Concerned about security? Rest assured.\nYour posting key never leaves this app.\nIt is securely stored on your device ONLY.\nNo one, including us, will have it.'); }, icon: Icon(Icons.help), ) diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index fd52e255..514a8d0a 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -70,6 +70,89 @@ class _MyAccountScreenState extends State { ScaffoldMessenger.of(context).showSnackBar(snackBar); } + AppBar _appBar(String username) { + return AppBar( + title: Row( + children: [ + CustomCircleAvatar( + height: 36, + width: 36, + url: 'https://images.hive.blog/u/$username/avatar', + ), + const SizedBox(width: 5), + Text(username), + ], + ), + actions: [ + IconButton( + onPressed: () { + logout(); + }, + icon: Icon(Icons.exit_to_app), + ) + ], + ); + } + + Widget _trailingActionOnVideoListItem(VideoDetails item, HiveUserData user) { + return item.status == 'published' + ? Icon(Icons.check, color: Colors.green) + : item.status == 'publish_manual' + ? IconButton( + onPressed: () { + loadVideoInfo(user, item.id); + }, + icon: Icon( + Icons.rocket_launch, + color: Colors.green, + ), + ) + : Icon( + Icons.hourglass_top, + color: Colors.blue, + ); + } + + Widget _videoListItem(VideoDetails item, HiveUserData user) { + return ListTile( + leading: Image.network( + item.thumbUrl, + ), + title: Text(item.title), + subtitle: Text(item.description.length > 30 + ? item.description.substring(0, 30) + : item.description), + trailing: _trailingActionOnVideoListItem(item, user), + onTap: () {}, + ); + } + + Widget _videosList(List items, HiveUserData user) { + return ListView.separated( + itemBuilder: (context, index) { + return _videoListItem(items[index], user); + }, + separatorBuilder: (context, index) => const Divider(), + itemCount: items.length, + ); + } + + Widget _videoFuture(HiveUserData user) { + return FutureBuilder( + future: loadVideos, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Center(child: const Text('Something went wrong')); + } else if (snapshot.hasData && + snapshot.connectionState == ConnectionState.done) { + return _videosList(snapshot.data as List, user); + } else { + return const LoadingScreen(); + } + }, + ); + } + @override Widget build(BuildContext context) { var user = Provider.of(context); @@ -80,78 +163,13 @@ class _MyAccountScreenState extends State { } var username = user?.username ?? 'Unknown'; return Scaffold( - appBar: AppBar( - title: Row( - children: [ - CustomCircleAvatar( - height: 36, - width: 36, - url: 'https://images.hive.blog/u/$username/avatar', - ), - const SizedBox(width: 5), - Text(user?.username ?? 'Unknown'), - ], - ), - actions: [ - IconButton( - onPressed: () { - logout(); - }, - icon: Icon(Icons.exit_to_app), - ) - ], - ), + appBar: _appBar(username), body: Container( child: user == null ? Center(child: const Text('Nothing')) : isLoading ? Center(child: const CircularProgressIndicator()) - : FutureBuilder( - future: loadVideos, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Center( - child: const Text('Something went wrong')); - } else if (snapshot.hasData && - snapshot.connectionState == ConnectionState.done) { - List items = - snapshot.data! as List; - return ListView.separated( - itemBuilder: (context, index) { - return ListTile( - leading: Image.network( - items[index].thumbUrl, - ), - title: Text(items[index].title), - subtitle: Text(items[index].description), - trailing: items[index].status == 'published' - ? Icon(Icons.check, color: Colors.green) - : items[index].status == 'publish_manual' - ? IconButton( - onPressed: () { - loadVideoInfo( - user, items[index].id); - }, - icon: Icon( - Icons.rocket_launch, - color: Colors.green, - ), - ) - : Icon( - Icons.hourglass_top, - color: Colors.blue, - ), - onTap: () {}, - ); - }, - separatorBuilder: (context, index) => const Divider(), - itemCount: items.length, - ); - } else { - return const LoadingScreen(); - } - }, - ), + : _videoFuture(user), ), ); } diff --git a/lib/src/screens/upload/upload_extra_screen.dart b/lib/src/screens/upload/upload_extra_screen.dart index 4dea33b1..42499168 100644 --- a/lib/src/screens/upload/upload_extra_screen.dart +++ b/lib/src/screens/upload/upload_extra_screen.dart @@ -13,12 +13,14 @@ class UploadExtraScreen extends StatefulWidget { required this.title, required this.description, required this.ipfsName, + required this.thumbUrl, }) : super(key: key); final String videoId; final String title; final String description; final String ipfsName; + final String? thumbUrl; @override State createState() => _UploadExtraScreenState(); @@ -34,6 +36,7 @@ class _UploadExtraScreenState extends State { var thumbUrl = ''; var tags = ''; var progress = 0.0; + void showError(String string) { var snackBar = SnackBar(content: Text('Error: $string')); ScaffoldMessenger.of(context).showSnackBar(snackBar); @@ -211,6 +214,9 @@ class _UploadExtraScreenState extends State { @override Widget build(BuildContext context) { var user = Provider.of(context); + if (user != null && thumbUrl.isEmpty && widget.thumbUrl != null) { + initiateUpload(user, XFile(widget.thumbUrl!)); + } return Scaffold( appBar: AppBar( title: const Text('Provide more info'), @@ -223,6 +229,7 @@ class _UploadExtraScreenState extends State { _tagField(), _notSafe(), _thumbnailPicker(user), + const Text('Tap to change video thumbnail'), ], ), floatingActionButton: isCompleting diff --git a/lib/src/screens/upload/upload_screen.dart b/lib/src/screens/upload/upload_screen.dart index a7ed32bc..cad0b03d 100644 --- a/lib/src/screens/upload/upload_screen.dart +++ b/lib/src/screens/upload/upload_screen.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/upload/upload_extra_screen.dart'; import 'package:acela/src/utils/communicator.dart'; @@ -5,6 +7,7 @@ import 'package:cross_file/cross_file.dart' show XFile; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:tus_client/tus_client.dart'; +import 'package:video_thumbnail/video_thumbnail.dart'; class UploadScreen extends StatefulWidget { const UploadScreen({ @@ -37,6 +40,7 @@ class _UploadScreenState extends State { var ipfsName = ''; var uploadStarted = false; var uploadComplete = false; + String? thumbUrl; @override void initState() { @@ -61,8 +65,10 @@ class _UploadScreenState extends State { print(client.uploadUrl.toString()); var url = client.uploadUrl.toString(); var ipfsName = url.replaceAll("${Communicator.fsServer}/", ""); + var pathImageThumb = await getThumbnail(widget.xFile.path); setState(() { this.ipfsName = ipfsName; + this.thumbUrl = pathImageThumb; uploadComplete = true; }); }, @@ -116,6 +122,18 @@ class _UploadScreenState extends State { ); } + Future getThumbnail(String path) async { + Directory tempDir = Directory.systemTemp; + var imagePath = await VideoThumbnail.thumbnailFile( + video: path, + thumbnailPath: tempDir.path, + imageFormat: ImageFormat.PNG, + maxWidth: 320, + quality: 100, + ); + return imagePath; + } + @override Widget build(BuildContext context) { var user = Provider.of(context); @@ -132,6 +150,7 @@ class _UploadScreenState extends State { title: title, description: description, ipfsName: ipfsName, + thumbUrl: thumbUrl, ); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 597aab9f..e43cf02d 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -16,11 +16,17 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:http/http.dart' as http; class Communicator { - // static const tsServer = "http://localhost:13050"; - static const tsServer = "http://10.0.2.2:13050"; + // Production + static const tsServer = "https://studio.3speak.tv"; + static const fsServer = "https://uploads.3speak.tv/files"; + + // Android + // static const fsServer = "http://10.0.2.2:1080/files"; + // static const tsServer = "http://10.0.2.2:13050"; - // static const fsServer = "https://uploads.3speak.tv/files"; - static const fsServer = "http://10.0.2.2:1080/files"; + // iOS + // static const tsServer = "http://localhost:13050"; + // static const fsServer = "http://localhost:1080/files"; Future fetchHiveInfo(String user, String permlink) async { var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); @@ -241,18 +247,23 @@ class Communicator { "Content-Type": "application/json" }; request.headers.addAll(map); - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - log("Successfully sent upload complete"); - var string = await response.stream.bytesToString(); - log('Video complete response is\n$string'); - return VideoUploadInfo.fromJsonString(string); - } else { - var string = await response.stream.bytesToString(); - var error = ErrorResponse.fromJsonString(string).error ?? - response.reasonPhrase.toString(); - log('Error from server is $error'); - throw error; + try { + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + log("Successfully sent upload complete"); + var string = await response.stream.bytesToString(); + log('Video complete response is\n$string'); + return VideoUploadInfo.fromJsonString(string); + } else { + var string = await response.stream.bytesToString(); + var error = ErrorResponse.fromJsonString(string).error ?? + response.reasonPhrase.toString(); + log('Error from server is $error'); + throw error; + } + } catch (e) { + log('Error from server is ${e.toString()}'); + rethrow; } } diff --git a/pubspec.lock b/pubspec.lock index 2b188a4f..b8999fba 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -959,6 +959,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.11+4" + video_thumbnail: + dependency: "direct main" + description: + name: video_thumbnail + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.0" visibility_detector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 35bd8069..d66d2c22 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,6 +55,7 @@ dependencies: url_launcher: ^6.0.20 video_player: ^2.2.14 video_player_web_hls: ^0.1.11+3 + video_thumbnail: ^0.5.0 dev_dependencies: flutter_test: From 339872ecfce19d9728156be1dfd76926837fb5f3 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 4 Jul 2022 08:39:36 +0530 Subject: [PATCH 089/466] version bump --- .flutter-plugins-dependencies | 2 +- .idea/Android-App.iml | 6 ++++++ .packages | 2 +- pubspec.yaml | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 3f35bbcc..97357a21 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-04 06:55:21.968881","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-04 08:36:30.734089","version":"3.0.4"} \ No newline at end of file diff --git a/.idea/Android-App.iml b/.idea/Android-App.iml index e6c2a2eb..6921902a 100644 --- a/.idea/Android-App.iml +++ b/.idea/Android-App.iml @@ -74,6 +74,12 @@ + + + + + + diff --git a/.packages b/.packages index 61922157..5de29984 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-07-03 20:00:47.065585. +# Generated by pub on 2022-07-04 08:36:22.222383. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ diff --git a/pubspec.yaml b/pubspec.yaml index d66d2c22..e28593ee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+12 +version: 1.0.1+20 environment: sdk: ">=2.15.1 <3.0.0" From 566c018d4ee5f913aba6f21b0bf29ee550d18a96 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sat, 9 Jul 2022 18:11:05 +0530 Subject: [PATCH 090/466] bug fix for posting the video. --- .flutter-plugins-dependencies | 2 +- .packages | 2 +- android/app/src/main/assets/index.html | 3 +- ios/Runner.xcodeproj/project.pbxproj | 27 +++++---- ios/Runner/Bridges/Auth/AuthBridge.swift | 1 + .../Auth/ValidateHiveKeyResponse.swift | 19 +++++++ ios/Runner/public/index.html | 55 +++++++++++-------- .../screens/my_account/my_account_screen.dart | 5 +- pubspec.yaml | 2 +- 9 files changed, 76 insertions(+), 40 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 97357a21..a8edc221 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-04 08:36:30.734089","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-09 18:10:56.508948","version":"3.0.4"} \ No newline at end of file diff --git a/.packages b/.packages index 5de29984..e4540721 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-07-04 08:36:22.222383. +# Generated by pub on 2022-07-09 18:10:56.426734. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ diff --git a/android/app/src/main/assets/index.html b/android/app/src/main/assets/index.html index 260a6351..fce39e2e 100644 --- a/android/app/src/main/assets/index.html +++ b/android/app/src/main/assets/index.html @@ -89,7 +89,8 @@ function postVideo(data, postingKey) { console.log(`Response received from server: ${data}`); - const result = JSON.parse(data).data; + const bdata = atob(data); + const result = JSON.parse(bdata).data; const json_metadata = JSON.stringify(result.json_metadata); const video = result.videoBody; let comment = { ...result.comment, json_metadata: json_metadata }; diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 392628f7..1453cc35 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -390,7 +390,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 14; + CURRENT_PROJECT_VERSION = 21; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -403,13 +403,14 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.0.1; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; }; @@ -420,7 +421,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 14; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -429,7 +430,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -468,7 +469,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 14; + CURRENT_PROJECT_VERSION = 21; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -487,12 +488,13 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.0.1; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; @@ -526,7 +528,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 14; + CURRENT_PROJECT_VERSION = 21; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -539,7 +541,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.0.1; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; SDKROOT = iphoneos; @@ -548,6 +550,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; @@ -558,7 +561,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 14; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -567,7 +570,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -584,7 +587,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 14; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -593,7 +596,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/ios/Runner/Bridges/Auth/AuthBridge.swift b/ios/Runner/Bridges/Auth/AuthBridge.swift index 00a44bdb..99f046af 100644 --- a/ios/Runner/Bridges/Auth/AuthBridge.swift +++ b/ios/Runner/Bridges/Auth/AuthBridge.swift @@ -53,6 +53,7 @@ class AuthBridge { result(FlutterMethodNotImplemented) return } + self?.postVideo(data: data, postingKey: password, result: result) default: debugPrint("do nothing") } }) diff --git a/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift b/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift index 8b939ed9..b6ceed0d 100644 --- a/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift +++ b/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift @@ -49,3 +49,22 @@ struct DecryptMemoResponse: Codable { return dataString } } + +struct PostVideoResponse: Codable { + let valid: Bool + let error: String + + static func jsonStringFrom(dict: [String: AnyObject]) -> String? { + guard + let valid = dict["valid"] as? Bool, + let error = dict["error"] as? String + else { return nil } + let response = PostVideoResponse( + valid: valid, + error: error + ) + guard let data = try? JSONEncoder().encode(response) else { return nil } + guard let dataString = String(data: data, encoding: .utf8) else { return nil } + return dataString + } +} diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index 4e5095b5..f497b583 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -1,17 +1,17 @@ - - - - - - 3Speak Acela - - - - - - + - + diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 514a8d0a..bba4541e 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; @@ -39,9 +40,11 @@ class _MyAccountScreenState extends State { }); try { var result = await Communicator().loadOperations(user, videoId); + var utf8data = utf8.encode(result); + final base64Str = base64.encode(utf8data); var platform = MethodChannel('com.example.acela/auth'); final String response = await platform.invokeMethod('postVideo', { - 'data': result, + 'data': base64Str, 'postingKey': user.postingKey, }); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); diff --git a/pubspec.yaml b/pubspec.yaml index e28593ee..a5204331 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.1+20 +version: 1.0.1+22 environment: sdk: ">=2.15.1 <3.0.0" From fdf5801832a275e6d358812fe3983f90f92ee966 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 18 Jul 2022 02:01:04 +0530 Subject: [PATCH 091/466] Push notifications work in progress. --- .flutter-plugins | 5 + .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 56 ++++++ .idea/libraries/Flutter_Plugins.xml | 5 + .packages | 9 +- .../kotlin/com/example/acela/MainActivity.kt | 5 + ios/Runner.xcodeproj/project.pbxproj | 6 +- lib/main.dart | 39 ++++ lib/src/models/my_account/my_devices.dart | 49 +++++ lib/src/screens/home_screen/home_screen.dart | 4 - .../account_settings_screen.dart | 69 +++++++ .../manage_notifications.dart | 184 ++++++++++++++++++ .../screens/my_account/my_account_screen.dart | 7 +- lib/src/utils/communicator.dart | 74 ++++++- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 49 +++++ pubspec.yaml | 2 + 17 files changed, 550 insertions(+), 17 deletions(-) create mode 100644 lib/src/models/my_account/my_devices.dart create mode 100644 lib/src/screens/my_account/account_settings/account_settings_screen.dart create mode 100644 lib/src/screens/my_account/account_settings/manage_notifications.dart diff --git a/.flutter-plugins b/.flutter-plugins index ddb47a22..0058c0cc 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,5 +1,10 @@ # This is a generated file; do not edit or check into version control. better_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/ +device_info_plus=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/ +device_info_plus_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/ +device_info_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/ +device_info_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/ +device_info_plus_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/ ffmpeg_kit_flutter=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/ file_picker=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/ firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index a8edc221..e4d2e2aa 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-09 18:10:56.508948","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-18 01:51:34.963182","version":"3.0.4"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index f33a8751..58045245 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -219,6 +219,48 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -576,6 +618,13 @@ + + + + + + @@ -1093,6 +1142,12 @@ + + + + + + @@ -1141,6 +1196,7 @@ + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 037d0155..4f2fb5f3 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -37,6 +37,11 @@ + + + + + diff --git a/.packages b/.packages index e4540721..b17bba77 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-07-09 18:10:56.426734. +# Generated by pub on 2022-07-18 01:51:33.806892. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ @@ -35,6 +35,12 @@ crypto:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/c csslib:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.17.1/lib/ cupertino_icons:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.5/lib/ dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.3/lib/ +device_info_plus:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/lib/ +device_info_plus_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/lib/ +device_info_plus_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/lib/ +device_info_plus_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_platform_interface-2.3.0+1/lib/ +device_info_plus_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/lib/ +device_info_plus_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/lib/ elliptic:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/elliptic-0.3.8/lib/ fake_async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.3.0/lib/ ffi:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.1.2/lib/ @@ -86,6 +92,7 @@ material_color_utilities:file:///Applications/flutter/flutter/.pub-cache/hosted/ meta:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib/ mime:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/mime-1.0.1/lib/ nested:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/nested-1.0.0/lib/ +overlay_support:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/overlay_support-2.0.1/lib/ package_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_config-2.0.2/lib/ path:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.1/lib/ path_provider:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.11/lib/ diff --git a/android/app/src/main/kotlin/com/example/acela/MainActivity.kt b/android/app/src/main/kotlin/com/example/acela/MainActivity.kt index 7e4472ad..6520d03e 100644 --- a/android/app/src/main/kotlin/com/example/acela/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/acela/MainActivity.kt @@ -35,6 +35,10 @@ import android.webkit.ValueCallback import android.webkit.WebResourceResponse import androidx.annotation.RequiresApi import androidx.webkit.WebViewAssetLoader +import android.webkit.WebChromeClient + + + class MainActivity: FlutterActivity() { var webView: WebView? = null @@ -73,6 +77,7 @@ class MainActivity: FlutterActivity() { webView?.visibility = View.GONE webView?.settings?.javaScriptEnabled = true webView?.settings?.domStorageEnabled = true + webView?.setWebChromeClient(WebChromeClient()) WebView.setWebContentsDebuggingEnabled(true) val assetLoader = WebViewAssetLoader.Builder() .addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(this)) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 1453cc35..89769d5d 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -421,7 +421,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 21; + CURRENT_PROJECT_VERSION = 22; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -561,7 +561,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 21; + CURRENT_PROJECT_VERSION = 22; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -587,7 +587,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 21; + CURRENT_PROJECT_VERSION = 22; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; diff --git a/lib/main.dart b/lib/main.dart index 737f130e..359c43c9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,10 @@ +import 'dart:io'; + import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -9,6 +12,15 @@ import 'package:provider/provider.dart'; import 'firebase_options.dart'; +class PushNotification { + PushNotification({ + this.title, + this.body, + }); + String? title; + String? body; +} + Future main() async { await dotenv.load(fileName: ".env"); WidgetsFlutterBinding.ensureInitialized(); @@ -25,6 +37,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { final Future _fbApp = Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + late final FirebaseMessaging _messaging; // Create storage static const storage = FlutterSecureStorage(); @@ -66,6 +79,32 @@ class _MyAppState extends State { } void loadData() async { + // 3. On iOS, this helps to take the user permissions + if (Platform.isIOS) { + NotificationSettings settings = await _messaging.requestPermission( + alert: true, + badge: true, + provisional: false, + sound: true, + ); + if (settings.authorizationStatus == AuthorizationStatus.authorized) { + print('User granted permission'); + } else { + print('User declined or has not accepted permission'); + } + } + FirebaseMessaging.onMessage.listen((RemoteMessage message) { + // Parse the message received + PushNotification notification = PushNotification( + title: message.notification?.title, + body: message.notification?.body, + ); + + setState(() { + _notificationInfo = notification; + _totalNotifications++; + }); + }); String? username = await storage.read(key: 'username'); String? postingKey = await storage.read(key: 'postingKey'); String? cookie = await storage.read(key: 'cookie'); diff --git a/lib/src/models/my_account/my_devices.dart b/lib/src/models/my_account/my_devices.dart new file mode 100644 index 00000000..e94904b5 --- /dev/null +++ b/lib/src/models/my_account/my_devices.dart @@ -0,0 +1,49 @@ +import 'dart:convert'; + +import 'package:acela/src/utils/safe_convert.dart'; + +class MyDevices { + final bool success; + final List data; + + MyDevices({ + this.success = false, + required this.data, + }); + + factory MyDevices.fromJson(Map? json) => MyDevices( + success: asBool(json, 'success'), + data: asList(json, 'data') + .map((e) => MyDevicesDataItem.fromJson(e)) + .toList(), + ); + + factory MyDevices.fromString(String string) => + MyDevices.fromJson(json.decode(string)); + + Map toJson() => { + 'success': success, + 'data': data.map((e) => e.toJson()), + }; +} + +class MyDevicesDataItem { + final String token; + final String deviceName; + + MyDevicesDataItem({ + this.token = "", + this.deviceName = "", + }); + + factory MyDevicesDataItem.fromJson(Map? json) => + MyDevicesDataItem( + token: asString(json, 'token'), + deviceName: asString(json, 'deviceName'), + ); + + Map toJson() => { + 'token': token, + 'deviceName': deviceName, + }; +} diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 43cad90f..352bfa42 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -17,7 +17,6 @@ import 'package:cross_file/cross_file.dart' show XFile; import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; import 'package:ffmpeg_kit_flutter/media_information_session.dart'; import 'package:file_picker/file_picker.dart'; -import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' show get; import 'package:provider/provider.dart'; @@ -186,9 +185,6 @@ class _HomeScreenState extends State { .toJson()); var cookie = await Communicator().getValidCookie(user); log('Cookie is $cookie'); - final fcmToken = await FirebaseMessaging.instance.getToken(); - log('FCM Token is $fcmToken'); - await Communicator().addToken(user, fcmToken ?? ""); var response = await Communicator() .prepareVideo(user, fileInfoInString, cookie); log('Response file name is ${response.filename}'); diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart new file mode 100644 index 00000000..8c4df129 --- /dev/null +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -0,0 +1,69 @@ +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/screens/my_account/account_settings/manage_notifications.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:provider/provider.dart'; + +class AccountSettingsScreen extends StatefulWidget { + const AccountSettingsScreen({Key? key}) : super(key: key); + + @override + State createState() => _AccountSettingsScreenState(); +} + +class _AccountSettingsScreenState extends State { + void logout() async { + // Create storage + const storage = FlutterSecureStorage(); + await storage.delete(key: 'username'); + await storage.delete(key: 'postingKey'); + server.updateHiveUserData(null); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + } + + Widget _changeTheme(BuildContext context) { + var isDarkMode = Provider.of(context); + return ListTile( + leading: !isDarkMode + ? const Icon(Icons.wb_sunny) + : const Icon(Icons.mode_night), + title: const Text("Change Theme"), + onTap: () async { + server.changeTheme(isDarkMode); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Settings'), + ), + body: SafeArea( + child: ListView( + children: [ + ListTile( + leading: const Icon(Icons.notifications), + title: const Text('Manage Notifications'), + onTap: () { + var screen = ManageNotificationsScreen(); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + ), + _changeTheme(context), + ListTile( + leading: const Icon(Icons.logout), + title: const Text('Log Out'), + onTap: () { + logout(); + }, + ), + ], + ), + ), + ); + } +} diff --git a/lib/src/screens/my_account/account_settings/manage_notifications.dart b/lib/src/screens/my_account/account_settings/manage_notifications.dart new file mode 100644 index 00000000..12b05595 --- /dev/null +++ b/lib/src/screens/my_account/account_settings/manage_notifications.dart @@ -0,0 +1,184 @@ +import 'dart:developer'; +import 'dart:io'; + +import 'package:acela/src/models/my_account/my_devices.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ManageNotificationsScreen extends StatefulWidget { + const ManageNotificationsScreen({Key? key}) : super(key: key); + + @override + State createState() => + _ManageNotificationsScreenState(); +} + +class _ManageNotificationsScreenState extends State { + Future>? getDevices; + var isDeletingOrSending = false; + + void showError(String string) { + var snackBar = SnackBar(content: Text('Error: $string')); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + void deleteToken(String token, HiveUserData user) async { + setState(() { + isDeletingOrSending = true; + }); + try { + await Communicator().deleteToken(user, token); + } catch (e) { + showError("Something went wrong\n${e.toString()}"); + } finally { + setState(() { + isDeletingOrSending = false; + getDevices = null; + }); + } + } + + Widget _deviceList(List list, HiveUserData user) { + if (list.isEmpty) { + return Center( + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: 220), + child: Text( + "No devices are added for notifications.\n\nTap on Plus, to get notified when your video finishes the processing and ready for publishing.", + textAlign: TextAlign.center, + ), + ), + ); + } + return Container( + margin: EdgeInsets.only(top: 10), + child: ListView.separated( + itemBuilder: (c, i) { + var tokenSuffix = list[i].token.substring(list[i].token.length - 10); + return ListTile( + leading: const Icon(Icons.phone_android), + subtitle: Text("Push Token ending with $tokenSuffix"), + trailing: IconButton( + onPressed: () { + deleteToken(list[i].token, user); + }, + icon: const Icon(Icons.delete), + ), + title: Text(list[i].deviceName), + ); + }, + separatorBuilder: (c, i) => Divider(), + itemCount: list.length, + ), + ); + } + + Widget _futureForDevices(HiveUserData user) { + return FutureBuilder( + future: getDevices, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Center(child: const Text('Something went wrong')); + } else if (snapshot.hasData && + snapshot.connectionState == ConnectionState.done) { + return _deviceList(snapshot.data as List, user); + } else { + return const LoadingScreen(); + } + }, + ); + } + + void registerForNotification(HiveUserData user) async { + setState(() { + isDeletingOrSending = true; + }); + try { + final fcmToken = await FirebaseMessaging.instance.getToken(); + var model = ''; + DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); + if (Platform.isAndroid) { + AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; + print('Running on ${androidInfo.model}'); + model = androidInfo.model ?? 'Some Android Device'; + } else if (Platform.isIOS) { + IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo; + print('Running on ${iosDeviceInfo.model}'); + model = iosDeviceInfo.model ?? 'Some iOS Device'; + } else { + model = 'Unknown Device type'; + } + log('FCM Token is $fcmToken'); + await Communicator().addToken(user, fcmToken ?? "", model); + } catch (e) { + showError("Something went wrong\n${e.toString()}"); + } finally { + setState(() { + isDeletingOrSending = false; + getDevices = null; + }); + } + } + + void sendTestNotification(HiveUserData user) async { + // testTokens + setState(() { + isDeletingOrSending = true; + }); + try { + await Communicator().testTokens(user); + } catch (e) { + showError("Something went wrong\n${e.toString()}"); + } finally { + setState(() { + isDeletingOrSending = false; + }); + } + } + + @override + Widget build(BuildContext context) { + var user = Provider.of(context); + if (user == null) { + return Scaffold( + appBar: AppBar( + title: const Text('Manage Notifications'), + ), + body: SafeArea( + child: const Text('Please re-login'), + ), + ); + } + if (getDevices == null) { + setState(() { + getDevices = Communicator().loadDevices(user); + }); + } + return Scaffold( + appBar: AppBar( + title: const Text('Manage Notifications'), + actions: isDeletingOrSending + ? [] + : [IconButton(onPressed: () {sendTestNotification(user);}, icon: Icon(Icons.notifications))], + ), + body: SafeArea( + child: isDeletingOrSending + ? const Center(child: CircularProgressIndicator()) + : _futureForDevices(user), + ), + floatingActionButton: isDeletingOrSending + ? null + : FloatingActionButton( + onPressed: () { + registerForNotification(user); + }, + child: const Icon(Icons.add), + ), + ); + } +} diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index bba4541e..5e63cd92 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -5,6 +5,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; +import 'package:acela/src/screens/my_account/account_settings/account_settings_screen.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; @@ -89,9 +90,11 @@ class _MyAccountScreenState extends State { actions: [ IconButton( onPressed: () { - logout(); + var screen = AccountSettingsScreen(); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); }, - icon: Icon(Icons.exit_to_app), + icon: Icon(Icons.settings), ) ], ); diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index e43cf02d..be782f7f 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -5,6 +5,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/login/memo_response.dart'; +import 'package:acela/src/models/my_account/my_devices.dart'; import 'package:acela/src/models/my_account/video_ops.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; @@ -17,12 +18,12 @@ import 'package:http/http.dart' as http; class Communicator { // Production - static const tsServer = "https://studio.3speak.tv"; - static const fsServer = "https://uploads.3speak.tv/files"; + // static const tsServer = "https://studio.3speak.tv"; + // static const fsServer = "https://uploads.3speak.tv/files"; // Android - // static const fsServer = "http://10.0.2.2:1080/files"; - // static const tsServer = "http://10.0.2.2:13050"; + static const fsServer = "http://10.0.2.2:1080/files"; + static const tsServer = "http://10.0.2.2:13050"; // iOS // static const tsServer = "http://localhost:13050"; @@ -177,10 +178,10 @@ class Communicator { } } - Future addToken(HiveUserData user, String token) async { + Future addToken(HiveUserData user, String token, String model) async { var request = http.Request( 'POST', Uri.parse('${Communicator.tsServer}/mobile/api/token/add')); - request.body = "{\"token\": \"$token\"}"; + request.body = "{\"token\": \"$token\", \"deviceName\": \"$model\"}"; Map map = { "cookie": user.cookie ?? "", "Content-Type": "application/json" @@ -221,6 +222,27 @@ class Communicator { } } + Future testTokens(HiveUserData user) async { + var request = http.Request( + 'GET', Uri.parse('${Communicator.tsServer}/mobile/api/token/test')); + Map map = { + "cookie": user.cookie ?? "", + "Content-Type": "application/json" + }; + request.headers.addAll(map); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + log("Successfully un-registered token"); + return; + } else { + var string = await response.stream.bytesToString(); + var error = ErrorResponse.fromJsonString(string).error ?? + response.reasonPhrase.toString(); + log('Error from server is $error'); + throw error; + } + } + Future uploadComplete({ required HiveUserData user, required String videoId, @@ -310,6 +332,46 @@ class Communicator { } } + Future> loadDevices(HiveUserData user) async { + var cookie = await getValidCookie(user); + var request = http.Request( + 'GET', Uri.parse('${Communicator.tsServer}/mobile/api/token/list')); + Map map = { + "cookie": cookie, + "Content-Type": "application/json" + }; + request.headers.addAll(map); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + return MyDevices.fromString(string).data; + } else { + var string = await response.stream.bytesToString(); + var error = ErrorResponse.fromJsonString(string).error ?? + response.reasonPhrase.toString(); + log('Error from server is $error'); + throw error; + } + } + + Future deleteToken(HiveUserData user, String token) async { + var cookie = await getValidCookie(user); + var request = http.Request( + 'POST', Uri.parse('${Communicator.tsServer}/mobile/api/token/remove')); + request.body = "{\"token\": \"$token\"}"; + Map map = { + "cookie": cookie, + "Content-Type": "application/json" + }; + request.headers.addAll(map); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + return; + } else { + throw response.reasonPhrase.toString(); + } + } + Future updatePublishState(HiveUserData user, String videoId) async { var cookie = await getValidCookie(user); var request = http.Request('POST', diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 38470c8c..da2a14b4 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import device_info_plus_macos import ffmpeg_kit_flutter import firebase_core import firebase_messaging @@ -15,6 +16,7 @@ import url_launcher_macos import wakelock_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) diff --git a/pubspec.lock b/pubspec.lock index b8999fba..9bfe80cd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -218,6 +218,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.3" + device_info_plus: + dependency: "direct main" + description: + name: device_info_plus + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + device_info_plus_linux: + dependency: transitive + description: + name: device_info_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + device_info_plus_macos: + dependency: transitive + description: + name: device_info_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.3" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0+1" + device_info_plus_web: + dependency: transitive + description: + name: device_info_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + device_info_plus_windows: + dependency: transitive + description: + name: device_info_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" elliptic: dependency: "direct main" description: @@ -569,6 +611,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" + overlay_support: + dependency: "direct main" + description: + name: overlay_support + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" package_config: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a5204331..4aaec2d1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: bs58check: ^1.0.2 chewie: ^1.3.0 crypto: ^3.0.2 + device_info_plus: ^4.0.0 elliptic: ^0.3.8 ffmpeg_kit_flutter: ^4.5.1 file_picker: ^4.5.1 @@ -48,6 +49,7 @@ dependencies: http: ^0.13.4 intl: ^0.17.0 json_annotation: ^4.4.0 + overlay_support: ^2.0.1 provider: ^6.0.2 share_plus: ^4.0.4 timeago: ^3.1.0 From 083641dea4af47ba6da87f2c1dbc695921187531 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 18 Jul 2022 10:30:03 +0530 Subject: [PATCH 092/466] Firebase cloud messaging related changes. --- .flutter-plugins-dependencies | 2 +- lib/main.dart | 80 +++++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index e4d2e2aa..acf1f14f 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-18 01:51:34.963182","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-18 10:28:09.973502","version":"3.0.4"} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 359c43c9..852976d1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; @@ -8,6 +6,7 @@ import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:overlay_support/overlay_support.dart'; import 'package:provider/provider.dart'; import 'firebase_options.dart'; @@ -35,19 +34,17 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - final Future _fbApp = - Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + late final Future _futureToLoadData; late final FirebaseMessaging _messaging; // Create storage - static const storage = FlutterSecureStorage(); Widget futureBuilder(Widget withWidget) { return FutureBuilder( - future: _fbApp, + future: _futureToLoadData, builder: (context, snapshot) { if (snapshot.hasError) { return const Text('Firebase not initialized'); - } else if (snapshot.hasData) { + } else if (snapshot.connectionState == ConnectionState.done) { return withWidget; } else { return const CircularProgressIndicator(); @@ -59,14 +56,16 @@ class _MyAppState extends State { // This widget is the root of your application. @override Widget build(BuildContext context) { - return futureBuilder( - StreamProvider.value( - value: server.hiveUserData, - initialData: null, - child: StreamProvider.value( - value: server.theme, - initialData: true, - child: const AcelaApp(), + return OverlaySupport.global( + child: futureBuilder( + StreamProvider.value( + value: server.hiveUserData, + initialData: null, + child: StreamProvider.value( + value: server.theme, + initialData: true, + child: const AcelaApp(), + ), ), ), ); @@ -75,36 +74,55 @@ class _MyAppState extends State { @override void initState() { super.initState(); - loadData(); + _futureToLoadData = loadData(); } - void loadData() async { - // 3. On iOS, this helps to take the user permissions - if (Platform.isIOS) { + Future handlingNotification() async { + try { + // 3. On iOS, this helps to take the user permissions NotificationSettings settings = await _messaging.requestPermission( alert: true, - badge: true, + badge: false, provisional: false, sound: true, ); if (settings.authorizationStatus == AuthorizationStatus.authorized) { print('User granted permission'); + FirebaseMessaging.onMessage.listen((RemoteMessage message) { + // Parse the message received + PushNotification notification = PushNotification( + title: message.notification?.title, + body: message.notification?.body, + ); + + setState(() { + showSimpleNotification( + Text(notification.title ?? "No title for notification"), + // leading: NotificationBadge(totalNotifications: _totalNotifications), + subtitle: Text(notification.body ?? + "No text provided for info of notification"), + background: Colors.cyan.shade700, + duration: Duration(seconds: 2), + ); + }); + }); } else { print('User declined or has not accepted permission'); } + } catch (e) { + print("Something went wrong in setting up fcm ${e.toString()}"); } - FirebaseMessaging.onMessage.listen((RemoteMessage message) { - // Parse the message received - PushNotification notification = PushNotification( - title: message.notification?.title, - body: message.notification?.body, - ); + } - setState(() { - _notificationInfo = notification; - _totalNotifications++; - }); - }); + Future loadData() async { + // setup firebase + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform); + _messaging = FirebaseMessaging.instance; + // handle notifications + await handlingNotification(); + // load storage + const storage = FlutterSecureStorage(); String? username = await storage.read(key: 'username'); String? postingKey = await storage.read(key: 'postingKey'); String? cookie = await storage.read(key: 'cookie'); From f8fd4f4b7b52df87e03f3a47086f185c32db3e79 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 18 Jul 2022 12:14:20 +0530 Subject: [PATCH 093/466] minor bug fixes. --- .flutter-plugins-dependencies | 2 +- .packages | 2 +- ios/Podfile.lock | 6 ++++++ lib/main.dart | 10 +++++++++- lib/src/screens/upload/upload_screen.dart | 6 +++++- lib/src/utils/communicator.dart | 8 ++++---- 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index acf1f14f..49a26dff 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-18 10:28:09.973502","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-18 12:06:45.747125","version":"3.0.4"} \ No newline at end of file diff --git a/.packages b/.packages index b17bba77..b30fb13e 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-07-18 01:51:33.806892. +# Generated by pub on 2022-07-18 11:53:31.122652. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3e670098..fcfbd863 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -6,6 +6,8 @@ PODS: - HLSCachingReverseProxyServer - PINCache - Cache (6.0.0) + - device_info_plus (0.0.1): + - Flutter - DKImagePickerController/Core (4.3.3): - DKImagePickerController/ImageDataManager - DKImagePickerController/Resource @@ -156,6 +158,7 @@ PODS: DEPENDENCIES: - better_player (from `.symlinks/plugins/better_player/ios`) + - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - ffmpeg_kit_flutter (from `.symlinks/plugins/ffmpeg_kit_flutter/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) @@ -197,6 +200,8 @@ SPEC REPOS: EXTERNAL SOURCES: better_player: :path: ".symlinks/plugins/better_player/ios" + device_info_plus: + :path: ".symlinks/plugins/device_info_plus/ios" ffmpeg_kit_flutter: :path: ".symlinks/plugins/ffmpeg_kit_flutter/ios" file_picker: @@ -225,6 +230,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: better_player: 2406bfe8175203c7a46fa15f9d778d73b12e1646 Cache: 4ca7e00363fca5455f26534e5607634c820ffc2d + device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed DKImagePickerController: 72fd378f244cef3d27288e0aebf217a4467e4012 DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 ffmpeg-kit-ios-https: cec24d405b511e4f274980d8a9c751d384f89558 diff --git a/lib/main.dart b/lib/main.dart index 852976d1..249a57af 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -47,7 +47,15 @@ class _MyAppState extends State { } else if (snapshot.connectionState == ConnectionState.done) { return withWidget; } else { - return const CircularProgressIndicator(); + return MaterialApp( + title: 'Acela', + home: Scaffold( + appBar: AppBar(title: const Text('Acela')), + body: const Center( + child: CircularProgressIndicator(), + ), + ), + ); } }, ); diff --git a/lib/src/screens/upload/upload_screen.dart b/lib/src/screens/upload/upload_screen.dart index cad0b03d..90ff2e21 100644 --- a/lib/src/screens/upload/upload_screen.dart +++ b/lib/src/screens/upload/upload_screen.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; @@ -45,7 +46,10 @@ class _UploadScreenState extends State { @override void initState() { super.initState(); - initiateUpload(); + Timer.periodic(Duration(seconds: 1), (timer) { + timer.cancel(); + initiateUpload(); + }); } void initiateUpload() async { diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index be782f7f..b06bf922 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -18,12 +18,12 @@ import 'package:http/http.dart' as http; class Communicator { // Production - // static const tsServer = "https://studio.3speak.tv"; - // static const fsServer = "https://uploads.3speak.tv/files"; + static const tsServer = "https://studio.3speak.tv"; + static const fsServer = "https://uploads.3speak.tv/files"; // Android - static const fsServer = "http://10.0.2.2:1080/files"; - static const tsServer = "http://10.0.2.2:13050"; + // static const fsServer = "http://10.0.2.2:1080/files"; + // static const tsServer = "http://10.0.2.2:13050"; // iOS // static const tsServer = "http://localhost:13050"; From 9267deb8b8ca861cfe454fac8fd986227f23efa9 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 22 Jul 2022 13:02:23 +0530 Subject: [PATCH 094/466] login without hivejs --- .flutter-plugins | 50 ++-- .flutter-plugins-dependencies | 2 +- .idea/Android-App.iml | 6 + .idea/libraries/Dart_Packages.xml | 272 +++++++++--------- .idea/libraries/Flutter_Plugins.xml | 48 ++-- .packages | 126 ++++---- ios/Runner.xcodeproj/project.pbxproj | 6 +- lib/src/bloc/server.dart | 2 - .../hive_post_info/hive_user_posting_key.dart | 26 ++ .../communities_screen.dart | 4 +- .../community_details_screen.dart | 6 +- lib/src/screens/login/login_screen.dart | 25 +- lib/src/screens/search/search_screen.dart | 3 +- lib/src/screens/upload/upload_screen.dart | 4 +- .../follower_list_tile.dart | 4 +- .../user_channel_following.dart | 5 +- .../user_channel_profile.dart | 8 +- .../user_channel_screen.dart | 4 +- .../user_channel_videos.dart | 3 +- .../video_details_comments.dart | 5 +- .../video_details_screen.dart | 3 +- .../video_details_view_model.dart | 25 +- lib/src/utils/communicator.dart | 34 ++- lib/src/utils/priv_to_pub.dart | 8 + lib/src/widgets/list_tile_video.dart | 3 +- pubspec.lock | 152 +++++----- pubspec.yaml | 6 +- 27 files changed, 480 insertions(+), 360 deletions(-) create mode 100644 lib/src/models/hive_post_info/hive_user_posting_key.dart create mode 100644 lib/src/utils/priv_to_pub.dart diff --git a/.flutter-plugins b/.flutter-plugins index 0058c0cc..151a31a8 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -6,41 +6,41 @@ device_info_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartl device_info_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/ device_info_plus_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/ ffmpeg_kit_flutter=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/ -file_picker=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/ -firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/ -firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/ -firebase_messaging=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/ -firebase_messaging_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/ -flutter_plugin_android_lifecycle=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/ +file_picker=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/ +firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.20.0/ +firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.7.1/ +firebase_messaging=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.4/ +firebase_messaging_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.4/ +flutter_plugin_android_lifecycle=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/ flutter_secure_storage=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/ flutter_secure_storage_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/ flutter_secure_storage_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/ flutter_secure_storage_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/ flutter_secure_storage_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/ path_provider=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.11/ -path_provider_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/ -path_provider_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/ +path_provider_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/ +path_provider_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/ path_provider_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/ path_provider_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/ path_provider_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/ -share_plus=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/ +share_plus=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/ share_plus_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/ -share_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/ -share_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/ -share_plus_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/ -url_launcher=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.1.0/ -url_launcher_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/ -url_launcher_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/ -url_launcher_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/ -url_launcher_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/ -url_launcher_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/ -url_launcher_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/ -video_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.4.0/ -video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/ -video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/ -video_player_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/ +share_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/ +share_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/ +share_plus_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/ +url_launcher=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.1.5/ +url_launcher_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/ +url_launcher_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/ +url_launcher_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/ +url_launcher_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/ +url_launcher_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/ +url_launcher_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/ +video_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.4.5/ +video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/ +video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/ +video_player_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.11/ video_player_web_hls=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/ -video_thumbnail=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/ -wakelock=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/ +video_thumbnail=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/ +wakelock=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/ wakelock_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/ wakelock_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 49a26dff..4e8135c3 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-18 12:06:45.747125","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.20.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.20.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.20.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.7.1/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.4/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.11/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-22 12:56:51.472087","version":"3.0.4"} \ No newline at end of file diff --git a/.idea/Android-App.iml b/.idea/Android-App.iml index 6921902a..9caeb157 100644 --- a/.idea/Android-App.iml +++ b/.idea/Android-App.iml @@ -80,6 +80,12 @@ + + + + + + diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 58045245..d6d953c8 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -5,28 +5,28 @@ - - - - @@ -72,6 +72,13 @@ + + + + + + @@ -82,7 +89,7 @@ - @@ -96,14 +103,14 @@ - - @@ -124,7 +131,7 @@ - @@ -152,7 +159,7 @@ - @@ -180,14 +187,14 @@ - - @@ -201,7 +208,7 @@ - @@ -278,7 +285,7 @@ - @@ -306,56 +313,56 @@ - - - - - - - - @@ -383,14 +390,14 @@ - - @@ -467,7 +474,7 @@ - @@ -481,7 +488,7 @@ - @@ -516,14 +523,14 @@ - - @@ -551,14 +558,14 @@ - - @@ -607,7 +614,7 @@ - @@ -628,7 +635,7 @@ - @@ -649,14 +656,14 @@ - - @@ -709,10 +716,17 @@ + + + + + + - @@ -726,7 +740,7 @@ - @@ -747,7 +761,7 @@ - @@ -761,42 +775,42 @@ - - - - - - @@ -835,6 +849,13 @@ + + + + + + @@ -894,7 +915,7 @@ - @@ -908,56 +929,56 @@ - - - - - - - - @@ -968,45 +989,38 @@ - - - - - - - - - - - @@ -1020,7 +1034,7 @@ - @@ -1034,7 +1048,7 @@ - @@ -1083,7 +1097,7 @@ - @@ -1104,42 +1118,44 @@ - - - - - + + + + + + - + - - + + - + - + - - + + - + @@ -1150,22 +1166,22 @@ - + - - - - - - - - + + + + + + + + - - + + @@ -1174,34 +1190,34 @@ - + - + - - + + - - + + - + - + - - + + @@ -1209,19 +1225,20 @@ - + + - + - + - - - - - - + + + + + + @@ -1234,37 +1251,36 @@ - + - - - - - - - - + + + + + + + + - - - - - - + + + + + - + - + - + - + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 4f2fb5f3..b7b44156 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,47 +1,47 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.packages b/.packages index b30fb13e..d6e0cb8f 100644 --- a/.packages +++ b/.packages @@ -3,36 +3,37 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-07-18 11:53:31.122652. -_fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-39.0.0/lib/ -adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.1/lib/ -analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.0.0/lib/ -args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.0/lib/ +# Generated by pub on 2022-07-22 12:53:53.676655. +_fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-41.0.0/lib/ +adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.2/lib/ +analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.2.0/lib/ +args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.1/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ base_x:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/base_x-2.0.0/lib/ better_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/lib/ boolean_selector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/ bs58:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/bs58-1.0.2/lib/ bs58check:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/bs58check-1.0.2/lib/ +buffer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/buffer-1.1.1/lib/ build:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build-2.3.0/lib/ -build_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_config-1.0.0/lib/ +build_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_config-1.1.0/lib/ build_daemon:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_daemon-3.1.0/lib/ -build_resolvers:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_resolvers-2.0.8/lib/ -build_runner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner-2.1.10/lib/ +build_resolvers:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_resolvers-2.0.9/lib/ +build_runner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner-2.2.0/lib/ build_runner_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/build_runner_core-7.2.3/lib/ built_collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_collection-5.1.1/lib/ -built_value:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_value-8.2.3/lib/ +built_value:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/built_value-8.4.0/lib/ characters:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib/ charcode:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib/ checked_yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/checked_yaml-2.0.1/lib/ -chewie:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/chewie-1.3.2/lib/ +chewie:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/chewie-1.3.4/lib/ clock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib/ code_builder:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/code_builder-4.1.0/lib/ collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.16.0/lib/ -convert:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/convert-3.0.1/lib/ -cross_file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cross_file-0.3.3/lib/ +convert:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/convert-3.0.2/lib/ +cross_file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cross_file-0.3.3+1/lib/ crypto:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.2/lib/ -csslib:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.17.1/lib/ +csslib:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/csslib-0.17.2/lib/ cupertino_icons:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.5/lib/ dart_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.2.3/lib/ device_info_plus:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/lib/ @@ -43,23 +44,23 @@ device_info_plus_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub. device_info_plus_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/lib/ elliptic:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/elliptic-0.3.8/lib/ fake_async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.3.0/lib/ -ffi:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.1.2/lib/ +ffi:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.2.1/lib/ ffmpeg_kit_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/lib/ ffmpeg_kit_flutter_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter_platform_interface-0.2.1/lib/ file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib/ -file_picker:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.5.1/lib/ -firebase_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.15.0/lib/ -firebase_core_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_platform_interface-4.4.0/lib/ -firebase_core_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.6.4/lib/ -firebase_messaging:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.1/lib/ -firebase_messaging_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_platform_interface-3.5.1/lib/ -firebase_messaging_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.1/lib/ -fixnum:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fixnum-1.0.0/lib/ +file_picker:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/lib/ +firebase_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.20.0/lib/ +firebase_core_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_platform_interface-4.5.0/lib/ +firebase_core_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.7.1/lib/ +firebase_messaging:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.4/lib/ +firebase_messaging_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_platform_interface-3.5.4/lib/ +firebase_messaging_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.4/lib/ +fixnum:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fixnum-1.0.1/lib/ flutter:file:///Applications/flutter/flutter/packages/flutter/lib/ flutter_dotenv:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_dotenv-5.0.2/lib/ flutter_lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib/ -flutter_markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_markdown-0.6.10/lib/ -flutter_plugin_android_lifecycle:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.6/lib/ +flutter_markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_markdown-0.6.10+3/lib/ +flutter_plugin_android_lifecycle:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/lib/ flutter_secure_storage:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/lib/ flutter_secure_storage_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/lib/ flutter_secure_storage_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/lib/ @@ -70,34 +71,34 @@ flutter_test:file:///Applications/flutter/flutter/packages/flutter_test/lib/ flutter_web_plugins:file:///Applications/flutter/flutter/packages/flutter_web_plugins/lib/ flutter_widget_from_html_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_widget_from_html_core-0.8.5+3/lib/ font_awesome_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/font_awesome_flutter-10.1.0/lib/ -frontend_server_client:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/frontend_server_client-2.1.2/lib/ +frontend_server_client:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/frontend_server_client-2.1.3/lib/ fwfh_text_style:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fwfh_text_style-2.7.3+2/lib/ -glob:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/glob-2.0.2/lib/ +glob:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/glob-2.1.0/lib/ graphs:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/graphs-2.1.0/lib/ hex:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/hex-0.2.0/lib/ html:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/html-0.15.0/lib/ http:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http-0.13.4/lib/ -http_multi_server:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_multi_server-3.2.0/lib/ -http_parser:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_parser-4.0.0/lib/ +http_multi_server:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_multi_server-3.2.1/lib/ +http_parser:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_parser-4.0.1/lib/ intl:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/intl-0.17.0/lib/ io:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/io-1.0.3/lib/ js:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.4/lib/ -json_annotation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_annotation-4.5.0/lib/ -json_serializable:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_serializable-6.2.0/lib/ +json_annotation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_annotation-4.6.0/lib/ +json_serializable:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/json_serializable-6.3.1/lib/ lints:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib/ logging:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/logging-1.0.2/lib/ markdown:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/markdown-5.0.0/lib/ matcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.11/lib/ material_color_utilities:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.4/lib/ meta:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib/ -mime:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/mime-1.0.1/lib/ +mime:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/mime-1.0.2/lib/ nested:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/nested-1.0.0/lib/ overlay_support:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/overlay_support-2.0.1/lib/ -package_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_config-2.0.2/lib/ +package_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_config-2.1.0/lib/ path:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.1/lib/ path_provider:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.11/lib/ -path_provider_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.14/lib/ -path_provider_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.9/lib/ +path_provider_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/lib/ +path_provider_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/lib/ path_provider_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/lib/ path_provider_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/lib/ path_provider_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_platform_interface-2.0.4/lib/ @@ -105,24 +106,26 @@ path_provider_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub petitparser:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/petitparser-5.0.0/lib/ platform:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/platform-3.1.0/lib/ plugin_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2/lib/ -pool:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pool-1.5.0/lib/ +pointycastle:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pointycastle-3.6.1/lib/ +pool:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pool-1.5.1/lib/ process:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/process-4.2.4/lib/ -provider:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/provider-6.0.2/lib/ +provider:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/provider-6.0.3/lib/ pub_semver:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pub_semver-2.1.1/lib/ pubspec_parse:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/pubspec_parse-1.2.0/lib/ -share_plus:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.4/lib/ +share_plus:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/lib/ share_plus_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/lib/ -share_plus_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.0/lib/ -share_plus_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_platform_interface-3.0.2/lib/ -share_plus_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.0/lib/ -share_plus_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.0/lib/ -shelf:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.3.0/lib/ -shelf_web_socket:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-1.0.1/lib/ +share_plus_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/lib/ +share_plus_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_platform_interface-3.0.3/lib/ +share_plus_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/lib/ +share_plus_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/lib/ +shelf:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.3.1/lib/ +shelf_web_socket:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-1.0.2/lib/ sky_engine:file:///Applications/flutter/flutter/bin/cache/pkg/sky_engine/lib/ source_gen:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_gen-1.2.2/lib/ source_helper:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_helper-1.3.2/lib/ source_span:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.2/lib/ stack_trace:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib/ +steemdart_ecc:file:///Applications/flutter/flutter/.pub-cache/git/steemdart_ecc-150324d517552548bd07048febd25cf8173d996e/lib/ stream_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0/lib/ stream_transform:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/stream_transform-2.0.0/lib/ string_scanner:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib/ @@ -131,35 +134,34 @@ test_api:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org timeago:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timeago-3.2.2/lib/ timing:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/timing-1.0.0/lib/ tus_client:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/tus_client-1.0.2/lib/ -typed_data:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib/ +typed_data:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.1/lib/ universal_io:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/universal_io-2.0.4/lib/ -url_launcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.1.0/lib/ -url_launcher_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.16/lib/ -url_launcher_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/lib/ -url_launcher_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/lib/ -url_launcher_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/lib/ -url_launcher_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_platform_interface-2.0.5/lib/ -url_launcher_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/lib/ -url_launcher_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/lib/ +url_launcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.1.5/lib/ +url_launcher_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/lib/ +url_launcher_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/lib/ +url_launcher_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/lib/ +url_launcher_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/lib/ +url_launcher_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_platform_interface-2.1.0/lib/ +url_launcher_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/lib/ +url_launcher_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/lib/ vector_math:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.2/lib/ -very_good_analysis:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/very_good_analysis-2.4.0/lib/ -video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.4.0/lib/ -video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.2/lib/ -video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.3/lib/ -video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.2/lib/ -video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.8/lib/ +video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.4.5/lib/ +video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/lib/ +video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/lib/ +video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.3/lib/ +video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.11/lib/ video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/lib/ -video_thumbnail:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.0/lib/ +video_thumbnail:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/lib/ visibility_detector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/visibility_detector-0.3.3/lib/ -wakelock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.1+2/lib/ +wakelock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/lib/ wakelock_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/lib/ wakelock_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_platform_interface-0.3.0/lib/ wakelock_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/lib/ wakelock_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_windows-0.2.0/lib/ watcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/watcher-1.0.1/lib/ web_socket_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.2.0/lib/ -win32:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/win32-2.5.2/lib/ +win32:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/win32-2.6.1/lib/ xdg_directories:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/xdg_directories-0.2.0+1/lib/ xml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/xml-6.1.0/lib/ -yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/yaml-3.1.0/lib/ +yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/yaml-3.1.1/lib/ acela:lib/ diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 89769d5d..fb401383 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -421,7 +421,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 22; + CURRENT_PROJECT_VERSION = 23; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -561,7 +561,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 22; + CURRENT_PROJECT_VERSION = 23; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -587,7 +587,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 22; + CURRENT_PROJECT_VERSION = 23; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; diff --git a/lib/src/bloc/server.dart b/lib/src/bloc/server.dart index 9c9c769e..f6fabf32 100644 --- a/lib/src/bloc/server.dart +++ b/lib/src/bloc/server.dart @@ -21,8 +21,6 @@ class Server { return "https://images.hive.blog/320x160/$value"; } - final String hiveDomain = "https://api.hive.blog"; - final _controller = StreamController(); final _hiveUserDataController = StreamController(); diff --git a/lib/src/models/hive_post_info/hive_user_posting_key.dart b/lib/src/models/hive_post_info/hive_user_posting_key.dart new file mode 100644 index 00000000..c60c3b5a --- /dev/null +++ b/lib/src/models/hive_post_info/hive_user_posting_key.dart @@ -0,0 +1,26 @@ +import 'dart:convert'; + +import 'package:acela/src/utils/safe_convert.dart'; + +class HiveUserPostingKey { + final String publicPostingKey; + + HiveUserPostingKey({ + required this.publicPostingKey, + }); + + factory HiveUserPostingKey.fromJson(Map? json) { + var resultMap = asMap(json, 'result'); + var accounts = asList(resultMap, 'accounts'); + if (accounts.isEmpty) throw 'accounts is empty'; + var postingMap = asMap(accounts[0], 'posting'); + var keyAuthsTopLevel = asList(postingMap, 'key_auths'); + if (keyAuthsTopLevel.isEmpty) throw 'Posting Key auths top level empty'; + var firstKeyAuth = keyAuthsTopLevel[0] as List; + var postingPublicKey = firstKeyAuth[0] as String; + return HiveUserPostingKey(publicPostingKey: postingPublicKey); + } + + factory HiveUserPostingKey.fromString(String string) => + HiveUserPostingKey.fromJson(json.decode(string)); +} diff --git a/lib/src/screens/communities_screen/communities_screen.dart b/lib/src/screens/communities_screen/communities_screen.dart index b35d13b5..45d25767 100644 --- a/lib/src/screens/communities_screen/communities_screen.dart +++ b/lib/src/screens/communities_screen/communities_screen.dart @@ -2,6 +2,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/communities_models/request/communities_request_model.dart'; import 'package:acela/src/models/communities_models/response/communities_response_models.dart'; import 'package:acela/src/screens/communities_screen/community_details/community_details_screen.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/retry.dart'; @@ -21,7 +22,8 @@ class _CommunitiesScreenState extends State { var client = http.Client(); var body = CommunitiesRequestModel(params: CommunitiesRequestParams()) .toJsonString(); - var response = await client.post(Uri.parse(server.hiveDomain), body: body); + var response = + await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); if (response.statusCode == 200) { var communitiesResponse = communitiesResponseModelFromString(response.body); diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index 56bfce55..3cc84bea 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -9,6 +9,7 @@ import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; @@ -60,7 +61,8 @@ class _CommunityDetailScreenState extends State Future _loadDetails() async { var client = http.Client(); var body = CommunityDetailsRequest.forName(widget.name).toJsonString(); - var response = await client.post(Uri.parse(server.hiveDomain), body: body); + var response = + await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); if (response.statusCode == 200) { return CommunityDetailsResponse.fromString(response.body); } else { @@ -119,7 +121,7 @@ class _CommunityDetailScreenState extends State } void fetchHiveInfo(String user, String permlink) async { - var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index c47c5077..834c7c88 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -1,6 +1,7 @@ import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/utils/priv_to_pub.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -26,12 +27,10 @@ class _LoginScreenState extends State { isLoading = true; }); try { - final String result = await platform.invokeMethod('validate', { - 'username': username, - 'postingKey': postingKey, - }); - var response = LoginBridgeResponse.fromJsonString(result); - if (response.valid && response.error.isEmpty) { + var publicKey = await Communicator().getPublicKey(username); + var resultingKey = CryptoManager().privToPub(postingKey); + if (resultingKey == publicKey) { + // it is valid key debugPrint("Successful login"); await storage.write(key: 'username', value: username); await storage.write(key: 'postingKey', value: postingKey); @@ -44,12 +43,16 @@ class _LoginScreenState extends State { ), ); Navigator.of(context).pop(); + setState(() { + isLoading = false; + }); } else { - showError(response.error); + // it is NO valid key + showError('Not valid key.'); + setState(() { + isLoading = false; + }); } - setState(() { - isLoading = false; - }); } catch (e) { setState(() { isLoading = false; diff --git a/lib/src/screens/search/search_screen.dart b/lib/src/screens/search/search_screen.dart index 7f30dd08..b54433ae 100644 --- a/lib/src/screens/search/search_screen.dart +++ b/lib/src/screens/search/search_screen.dart @@ -9,6 +9,7 @@ import 'package:acela/src/models/search/search_response_models.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; @@ -71,7 +72,7 @@ class _SearchScreenState extends State { // fetch hive info void fetchHiveInfo(String user, String permlink) async { - var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", diff --git a/lib/src/screens/upload/upload_screen.dart b/lib/src/screens/upload/upload_screen.dart index 90ff2e21..cb5032b7 100644 --- a/lib/src/screens/upload/upload_screen.dart +++ b/lib/src/screens/upload/upload_screen.dart @@ -78,7 +78,9 @@ class _UploadScreenState extends State { }, onProgress: (progress) { print("Progress: $progress"); - this.progress = progress; + setState(() { + this.progress = progress / 100.0; + }); }, ); } diff --git a/lib/src/screens/user_channel_screen/follower_list_tile.dart b/lib/src/screens/user_channel_screen/follower_list_tile.dart index 87e8ecb5..3ddeeca7 100644 --- a/lib/src/screens/user_channel_screen/follower_list_tile.dart +++ b/lib/src/screens/user_channel_screen/follower_list_tile.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_profile/request/user_profile_request.dart'; import 'package:acela/src/models/user_profile/response/user_profile.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; @@ -23,7 +24,8 @@ class _FollowerListTileState extends State Future _loadUserProfile() async { var client = http.Client(); var body = UserProfileRequest.forOwner(widget.name).toJsonString(); - var response = await client.post(Uri.parse(server.hiveDomain), body: body); + var response = + await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); if (response.statusCode == 200) { return UserProfileResponse.fromString(response.body); } else { diff --git a/lib/src/screens/user_channel_screen/user_channel_following.dart b/lib/src/screens/user_channel_screen/user_channel_following.dart index 431a9270..c05e5777 100644 --- a/lib/src/screens/user_channel_screen/user_channel_following.dart +++ b/lib/src/screens/user_channel_screen/user_channel_following.dart @@ -1,7 +1,7 @@ -import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_profile/request/user_followers_request.dart'; import 'package:acela/src/models/user_profile/response/followers_and_following.dart'; import 'package:acela/src/screens/user_channel_screen/follower_list_tile.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; @@ -28,7 +28,8 @@ class _UserChannelFollowingWidgetState extends State var body = widget.isFollowers ? UserFollowerRequest.followers(widget.owner).toJsonString() : UserFollowerRequest.following(widget.owner).toJsonString(); - var response = await client.post(Uri.parse(server.hiveDomain), body: body); + var response = + await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); if (response.statusCode == 200) { return Followers.fromJsonString(response.body); } else { diff --git a/lib/src/screens/user_channel_screen/user_channel_profile.dart b/lib/src/screens/user_channel_screen/user_channel_profile.dart index 1ce4f947..6de0fecb 100644 --- a/lib/src/screens/user_channel_screen/user_channel_profile.dart +++ b/lib/src/screens/user_channel_screen/user_channel_profile.dart @@ -1,6 +1,6 @@ -import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_profile/request/user_profile_request.dart'; import 'package:acela/src/models/user_profile/response/user_profile.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; @@ -26,7 +26,8 @@ class _UserChannelProfileWidgetState extends State Future _loadUserProfile() async { var client = http.Client(); var body = UserProfileRequest.forOwner(widget.owner).toJsonString(); - var response = await client.post(Uri.parse(server.hiveDomain), body: body); + var response = + await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); if (response.statusCode == 200) { return UserProfileResponse.fromString(response.body); } else { @@ -67,7 +68,8 @@ class _UserChannelProfileWidgetState extends State builder: (context, snapshot) { if (snapshot.hasError) { return const Text('Error loading user profile'); - } else if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) { + } else if (snapshot.hasData && + snapshot.connectionState == ConnectionState.done) { var data = snapshot.data! as UserProfileResponse; return _descriptionMarkDown(_generateMarkDown(data)); } else { diff --git a/lib/src/screens/user_channel_screen/user_channel_screen.dart b/lib/src/screens/user_channel_screen/user_channel_screen.dart index 8628f67c..cece833f 100644 --- a/lib/src/screens/user_channel_screen/user_channel_screen.dart +++ b/lib/src/screens/user_channel_screen/user_channel_screen.dart @@ -61,13 +61,13 @@ class _UserChannelScreenState extends State actions: [ BottomSheetAction( title: const Text('Newest'), - onPressed: () { + onPressed: (context) { videoKey.currentState?.sortByNewest(); }, ), BottomSheetAction( title: const Text('Most Viewed'), - onPressed: () { + onPressed: (context) { videoKey.currentState?.sortByMostViewed(); }, ), diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart index 1551013c..46c9e73f 100644 --- a/lib/src/screens/user_channel_screen/user_channel_videos.dart +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -7,6 +7,7 @@ import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:acela/src/widgets/loading_screen.dart'; @@ -90,7 +91,7 @@ class UserChannelVideosState extends State // fetch hive info void fetchHiveInfo(String user, String permlink) async { - var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart index a301d6cd..c4269c76 100644 --- a/lib/src/screens/video_details_screen/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -1,7 +1,7 @@ -import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/screens/video_details_screen/hive_comment.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; @@ -23,7 +23,8 @@ class _VideoDetailsCommentsState extends State { var client = http.Client(); var body = hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); - var response = await client.post(Uri.parse(server.hiveDomain), body: body); + var response = + await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); if (response.statusCode == 200) { var hiveCommentsResponse = hiveCommentsFromString(response.body); var comments = hiveCommentsResponse.result; diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 88dac37e..6f452064 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -10,6 +10,7 @@ import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; import 'package:acela/src/screens/video_details_screen/video_details_info.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; @@ -72,7 +73,7 @@ class _VideoDetailsScreenState extends State { // fetch hive info Future fetchHiveInfoForThisVideo() async { - var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index 3b8691b6..f1460973 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -3,6 +3,7 @@ import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:http/http.dart' show get; import 'package:http/http.dart' as http; @@ -10,12 +11,10 @@ class VideoDetailsViewModel { String author; String permlink; - VideoDetailsViewModel( - {required this.author, required this.permlink}); + VideoDetailsViewModel({required this.author, required this.permlink}); Future getVideoDetails() async { - final endPoint = - "${server.domain}/apiv2/@$author/$permlink"; + final endPoint = "${server.domain}/apiv2/@$author/$permlink"; var response = await get(Uri.parse(endPoint)); if (response.statusCode == 200) { VideoDetails data = VideoDetails.fromJsonString(response.body); @@ -26,8 +25,7 @@ class VideoDetailsViewModel { } Future> getRecommendedVideos() async { - final endPoint = - "${server.domain}/apiv2/recommended?v=$author/$permlink"; + final endPoint = "${server.domain}/apiv2/recommended?v=$author/$permlink"; var response = await get(Uri.parse(endPoint)); if (response.statusCode == 200) { var data = videoRecommendationItemsFromJson(response.body); @@ -40,8 +38,9 @@ class VideoDetailsViewModel { Future> loadComments(String author, String permlink) async { var client = http.Client(); var body = - hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); - var response = await client.post(Uri.parse(server.hiveDomain), body: body); + hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); + var response = + await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); if (response.statusCode == 200) { var hiveCommentsResponse = hiveCommentsFromString(response.body); var comments = hiveCommentsResponse.result; @@ -51,7 +50,7 @@ class VideoDetailsViewModel { .where((e) => e.parentPermlink == comments[i].permlink) .isEmpty) { var newComments = - await loadComments(comments[i].author, comments[i].permlink); + await loadComments(comments[i].author, comments[i].permlink); comments.insertAll(i + 1, newComments); } } @@ -62,11 +61,13 @@ class VideoDetailsViewModel { } } - Future> loadFirstSetOfComments(String author, String permlink) async { + Future> loadFirstSetOfComments( + String author, String permlink) async { var client = http.Client(); var body = - hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); - var response = await client.post(Uri.parse(server.hiveDomain), body: body); + hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); + var response = + await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); if (response.statusCode == 200) { var hiveCommentsResponse = hiveCommentsFromString(response.body); var comments = hiveCommentsResponse.result; diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index b06bf922..f0b95035 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; +import 'package:acela/src/models/hive_post_info/hive_user_posting_key.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/login/memo_response.dart'; import 'package:acela/src/models/my_account/my_devices.dart'; @@ -18,19 +19,42 @@ import 'package:http/http.dart' as http; class Communicator { // Production - static const tsServer = "https://studio.3speak.tv"; - static const fsServer = "https://uploads.3speak.tv/files"; + // static const tsServer = "https://studio.3speak.tv"; + // static const fsServer = "https://uploads.3speak.tv/files"; // Android // static const fsServer = "http://10.0.2.2:1080/files"; // static const tsServer = "http://10.0.2.2:13050"; // iOS - // static const tsServer = "http://localhost:13050"; - // static const fsServer = "http://localhost:1080/files"; + static const tsServer = "http://localhost:13050"; + static const fsServer = "http://localhost:1080/files"; + + static const hiveApiUrl = 'https://api.hive.blog/'; + + Future getPublicKey(String user) async { + var request = http.Request('POST', Uri.parse(hiveApiUrl)); + request.body = json.encode({ + "id": 8, + "jsonrpc": "2.0", + "method": "database_api.find_accounts", + "params": { + "accounts": [user] + } + }); + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var responseBody = await response.stream.bytesToString(); + var key = HiveUserPostingKey.fromString(responseBody); + return key.publicPostingKey; + } else { + print(response.reasonPhrase); + throw response.reasonPhrase.toString(); + } + } Future fetchHiveInfo(String user, String permlink) async { - var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", diff --git a/lib/src/utils/priv_to_pub.dart b/lib/src/utils/priv_to_pub.dart new file mode 100644 index 00000000..0acfb142 --- /dev/null +++ b/lib/src/utils/priv_to_pub.dart @@ -0,0 +1,8 @@ +import 'package:steemdart_ecc/steemdart_ecc.dart'; + +class CryptoManager { + String privToPub(String privateKey) { + SteemPrivateKey pkey = SteemPrivateKey.fromString(privateKey); + return pkey.toPublicKey().toString(); + } +} diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index 44ce16c0..34f88077 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:provider/provider.dart'; @@ -59,7 +60,7 @@ class _ListTileVideoState extends State { } Future fetchHiveInfo(String user, String permlink) async { - var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", diff --git a/pubspec.lock b/pubspec.lock index 9bfe80cd..e6a04321 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,28 +7,28 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "39.0.0" + version: "41.0.0" adaptive_action_sheet: dependency: "direct main" description: name: adaptive_action_sheet url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.2.0" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.3.1" async: dependency: transitive description: @@ -71,6 +71,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.2" + buffer: + dependency: transitive + description: + name: buffer + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" build: dependency: transitive description: @@ -84,7 +91,7 @@ packages: name: build_config url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.0" build_daemon: dependency: transitive description: @@ -98,14 +105,14 @@ packages: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.0.9" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.10" + version: "2.2.0" build_runner_core: dependency: transitive description: @@ -126,7 +133,7 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.2.3" + version: "8.4.0" characters: dependency: transitive description: @@ -154,7 +161,7 @@ packages: name: chewie url: "https://pub.dartlang.org" source: hosted - version: "1.3.2" + version: "1.3.4" clock: dependency: transitive description: @@ -182,14 +189,14 @@ packages: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" cross_file: dependency: transitive description: name: cross_file url: "https://pub.dartlang.org" source: hosted - version: "0.3.3" + version: "0.3.3+1" crypto: dependency: "direct main" description: @@ -203,7 +210,7 @@ packages: name: csslib url: "https://pub.dartlang.org" source: hosted - version: "0.17.1" + version: "0.17.2" cupertino_icons: dependency: transitive description: @@ -280,7 +287,7 @@ packages: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.2.1" ffmpeg_kit_flutter: dependency: "direct main" description: @@ -308,56 +315,56 @@ packages: name: file_picker url: "https://pub.dartlang.org" source: hosted - version: "4.5.1" + version: "4.6.1" firebase_core: dependency: "direct main" description: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.20.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "4.5.0" firebase_core_web: dependency: transitive description: name: firebase_core_web url: "https://pub.dartlang.org" source: hosted - version: "1.6.4" + version: "1.7.1" firebase_messaging: dependency: "direct main" description: name: firebase_messaging url: "https://pub.dartlang.org" source: hosted - version: "11.4.1" + version: "11.4.4" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "3.5.1" + version: "3.5.4" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web url: "https://pub.dartlang.org" source: hosted - version: "2.4.1" + version: "2.4.4" fixnum: dependency: transitive description: name: fixnum url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" flutter: dependency: "direct main" description: flutter @@ -383,14 +390,14 @@ packages: name: flutter_markdown url: "https://pub.dartlang.org" source: hosted - version: "0.6.10" + version: "0.6.10+3" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle url: "https://pub.dartlang.org" source: hosted - version: "2.0.6" + version: "2.0.7" flutter_secure_storage: dependency: "direct main" description: @@ -463,7 +470,7 @@ packages: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" fwfh_text_style: dependency: transitive description: @@ -477,7 +484,7 @@ packages: name: glob url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" graphs: dependency: transitive description: @@ -512,14 +519,14 @@ packages: name: http_multi_server url: "https://pub.dartlang.org" source: hosted - version: "3.2.0" + version: "3.2.1" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.1" intl: dependency: "direct main" description: @@ -547,14 +554,14 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.5.0" + version: "4.6.0" json_serializable: dependency: "direct dev" description: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "6.2.0" + version: "6.3.1" lints: dependency: transitive description: @@ -603,7 +610,7 @@ packages: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" nested: dependency: transitive description: @@ -624,7 +631,7 @@ packages: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" path: dependency: transitive description: @@ -645,14 +652,14 @@ packages: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.14" + version: "2.0.16" path_provider_ios: dependency: transitive description: name: path_provider_ios url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.10" path_provider_linux: dependency: transitive description: @@ -702,13 +709,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.1" pool: dependency: transitive description: name: pool url: "https://pub.dartlang.org" source: hosted - version: "1.5.0" + version: "1.5.1" process: dependency: transitive description: @@ -722,7 +736,7 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "6.0.2" + version: "6.0.3" pub_semver: dependency: transitive description: @@ -743,7 +757,7 @@ packages: name: share_plus url: "https://pub.dartlang.org" source: hosted - version: "4.0.4" + version: "4.0.10" share_plus_linux: dependency: transitive description: @@ -757,42 +771,42 @@ packages: name: share_plus_macos url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.0.3" share_plus_web: dependency: transitive description: name: share_plus_web url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" share_plus_windows: dependency: transitive description: name: share_plus_windows url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" shelf: dependency: transitive description: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" sky_engine: dependency: transitive description: flutter @@ -826,6 +840,15 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.10.0" + steemdart_ecc: + dependency: "direct main" + description: + path: "." + ref: master + resolved-ref: "150324d517552548bd07048febd25cf8173d996e" + url: "https://github.com/anpigon/steemdart_ecc" + source: git + version: "0.4.3+3" stream_channel: dependency: transitive description: @@ -888,7 +911,7 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" universal_io: dependency: transitive description: @@ -902,56 +925,56 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.1.0" + version: "6.1.5" url_launcher_android: dependency: transitive description: name: url_launcher_android url: "https://pub.dartlang.org" source: hosted - version: "6.0.16" + version: "6.0.17" url_launcher_ios: dependency: transitive description: name: url_launcher_ios url: "https://pub.dartlang.org" source: hosted - version: "6.0.15" + version: "6.0.17" url_launcher_linux: dependency: transitive description: name: url_launcher_linux url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.1.0" url_launcher_web: dependency: transitive description: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.12" url_launcher_windows: dependency: transitive description: name: url_launcher_windows url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" vector_math: dependency: transitive description: @@ -959,48 +982,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" - very_good_analysis: - dependency: transitive - description: - name: very_good_analysis - url: "https://pub.dartlang.org" - source: hosted - version: "2.4.0" video_player: dependency: "direct main" description: name: video_player url: "https://pub.dartlang.org" source: hosted - version: "2.4.0" + version: "2.4.5" video_player_android: dependency: transitive description: name: video_player_android url: "https://pub.dartlang.org" source: hosted - version: "2.3.2" + version: "2.3.8" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation url: "https://pub.dartlang.org" source: hosted - version: "2.3.3" + version: "2.3.5" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "5.1.2" + version: "5.1.3" video_player_web: dependency: transitive description: name: video_player_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.0.11" video_player_web_hls: dependency: "direct main" description: @@ -1014,7 +1030,7 @@ packages: name: video_thumbnail url: "https://pub.dartlang.org" source: hosted - version: "0.5.0" + version: "0.5.2" visibility_detector: dependency: transitive description: @@ -1028,7 +1044,7 @@ packages: name: wakelock url: "https://pub.dartlang.org" source: hosted - version: "0.6.1+2" + version: "0.6.2" wakelock_macos: dependency: transitive description: @@ -1077,7 +1093,7 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.5.2" + version: "2.6.1" xdg_directories: dependency: transitive description: @@ -1098,7 +1114,7 @@ packages: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.1.1" sdks: dart: ">=2.17.0 <3.0.0" - flutter: ">=2.12.0" + flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 4aaec2d1..27171534 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.1+22 +version: 1.0.1+23 environment: sdk: ">=2.15.1 <3.0.0" @@ -52,6 +52,10 @@ dependencies: overlay_support: ^2.0.1 provider: ^6.0.2 share_plus: ^4.0.4 + steemdart_ecc: + git: + url: https://github.com/anpigon/steemdart_ecc + ref: master timeago: ^3.1.0 tus_client: ^1.0.2 url_launcher: ^6.0.20 From d12b8de69acdfba089c2f0e2caf95e3b7f91e961 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sat, 23 Jul 2022 20:12:12 +0530 Subject: [PATCH 095/466] bug fixes for video upload. --- .flutter-plugins | 6 +- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 60 ++---------- .idea/libraries/Flutter_Plugins.xml | 6 +- .packages | 14 +-- ios/Podfile.lock | 90 +----------------- ios/Runner/AcelaWebViewController.swift | 2 +- ios/Runner/public/index.html | 2 +- lib/firebase_options.dart | 67 ------------- lib/generated_plugin_registrant.dart | 7 +- lib/main.dart | 88 +++++++++-------- lib/src/models/login/memo_serializer.dart | 7 ++ .../communities_screen.dart | 5 +- .../community_details_screen.dart | 15 ++- lib/src/screens/home_screen/home_screen.dart | 17 ++++ .../home_screen/home_screen_widgets.dart | 5 +- .../leaderboard_screen.dart | 5 +- lib/src/screens/login/login_screen.dart | 2 +- .../account_settings_screen.dart | 19 ++-- .../manage_notifications.dart | 95 ++++++++++--------- .../screens/my_account/my_account_screen.dart | 21 +++- .../screens/upload/upload_extra_screen.dart | 11 ++- .../user_channel_following.dart | 5 +- .../user_channel_profile.dart | 5 +- .../user_channel_videos.dart | 5 +- .../video_details_screen.dart | 8 +- lib/src/utils/communicator.dart | 10 +- lib/src/utils/crypto_manager.dart | 21 ++++ lib/src/utils/priv_to_pub.dart | 8 -- lib/src/widgets/loading_screen.dart | 29 ++++-- macos/Flutter/GeneratedPluginRegistrant.swift | 4 - pubspec.lock | 48 +--------- pubspec.yaml | 2 - 33 files changed, 270 insertions(+), 421 deletions(-) delete mode 100644 lib/firebase_options.dart create mode 100644 lib/src/models/login/memo_serializer.dart create mode 100644 lib/src/utils/crypto_manager.dart delete mode 100644 lib/src/utils/priv_to_pub.dart diff --git a/.flutter-plugins b/.flutter-plugins index 151a31a8..49982c00 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -7,10 +7,6 @@ device_info_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlan device_info_plus_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/ ffmpeg_kit_flutter=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/ file_picker=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/ -firebase_core=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.20.0/ -firebase_core_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.7.1/ -firebase_messaging=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.4/ -firebase_messaging_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.4/ flutter_plugin_android_lifecycle=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/ flutter_secure_storage=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/ flutter_secure_storage_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/ @@ -38,7 +34,7 @@ url_launcher_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlan video_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.4.5/ video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/ video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/ -video_player_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.11/ +video_player_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/ video_player_web_hls=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/ video_thumbnail=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/ wakelock=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 4e8135c3..e6b77d46 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.20.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.20.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"firebase_core","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.20.0/","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.4/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"firebase_core_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.7.1/","dependencies":[]},{"name":"firebase_messaging_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.4/","dependencies":["firebase_core_web"]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.11/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-22 12:56:51.472087","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-23 18:49:33.866142","version":"3.0.4"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index d6d953c8..9c1d0cde 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -5,7 +5,7 @@ - @@ -19,7 +19,7 @@ - @@ -317,48 +317,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1020,7 +978,7 @@ - @@ -1126,9 +1084,9 @@ - + - + @@ -1171,12 +1129,6 @@ - - - - - - @@ -1266,7 +1218,7 @@ - + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index b7b44156..b2d8c2e2 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -19,29 +19,25 @@ - - - - - + diff --git a/.packages b/.packages index d6e0cb8f..cc349521 100644 --- a/.packages +++ b/.packages @@ -3,10 +3,10 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-07-22 12:53:53.676655. -_fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-41.0.0/lib/ +# Generated by pub on 2022-07-23 08:25:31.906225. +_fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-42.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.2/lib/ -analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.2.0/lib/ +analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.3.0/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.1/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ base_x:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/base_x-2.0.0/lib/ @@ -49,12 +49,6 @@ ffmpeg_kit_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.da ffmpeg_kit_flutter_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter_platform_interface-0.2.1/lib/ file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib/ file_picker:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/lib/ -firebase_core:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.20.0/lib/ -firebase_core_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_platform_interface-4.5.0/lib/ -firebase_core_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.7.1/lib/ -firebase_messaging:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-11.4.4/lib/ -firebase_messaging_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_platform_interface-3.5.4/lib/ -firebase_messaging_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging_web-2.4.4/lib/ fixnum:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fixnum-1.0.1/lib/ flutter:file:///Applications/flutter/flutter/packages/flutter/lib/ flutter_dotenv:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_dotenv-5.0.2/lib/ @@ -149,7 +143,7 @@ video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/lib/ video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/lib/ video_player_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_platform_interface-5.1.3/lib/ -video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.11/lib/ +video_player_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/lib/ video_player_web_hls:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/lib/ video_thumbnail:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/lib/ visibility_detector:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/visibility_detector-0.3.3/lib/ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index fcfbd863..4deb4679 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -49,41 +49,6 @@ PODS: - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter - - Firebase/CoreOnly (8.15.0): - - FirebaseCore (= 8.15.0) - - Firebase/Messaging (8.15.0): - - Firebase/CoreOnly - - FirebaseMessaging (~> 8.15.0) - - firebase_core (1.15.0): - - Firebase/CoreOnly (= 8.15.0) - - Flutter - - firebase_messaging (11.4.1): - - Firebase/Messaging (= 8.15.0) - - firebase_core - - Flutter - - FirebaseCore (8.15.0): - - FirebaseCoreDiagnostics (~> 8.0) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/Logger (~> 7.7) - - FirebaseCoreDiagnostics (8.15.0): - - GoogleDataTransport (~> 9.1) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/Logger (~> 7.7) - - nanopb (~> 2.30908.0) - - FirebaseInstallations (8.15.0): - - FirebaseCore (~> 8.0) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/UserDefaults (~> 7.7) - - PromisesObjC (< 3.0, >= 1.2) - - FirebaseMessaging (8.15.0): - - FirebaseCore (~> 8.0) - - FirebaseInstallations (~> 8.0) - - GoogleDataTransport (~> 9.1) - - GoogleUtilities/AppDelegateSwizzler (~> 7.7) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/Reachability (~> 7.7) - - GoogleUtilities/UserDefaults (~> 7.7) - - nanopb (~> 2.30908.0) - Flutter (1.0.0) - flutter_secure_storage (3.3.1): - Flutter @@ -91,27 +56,6 @@ PODS: - GCDWebServer (3.5.4): - GCDWebServer/Core (= 3.5.4) - GCDWebServer/Core (3.5.4) - - GoogleDataTransport (9.1.4): - - GoogleUtilities/Environment (~> 7.7) - - nanopb (< 2.30910.0, >= 2.30908.0) - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/AppDelegateSwizzler (7.7.0): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Environment (7.7.0): - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.7.0): - - GoogleUtilities/Environment - - GoogleUtilities/Network (7.7.0): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.7.0)" - - GoogleUtilities/Reachability (7.7.0): - - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (7.7.0): - - GoogleUtilities/Logger - HLSCachingReverseProxyServer (0.1.0): - GCDWebServer (~> 3.5) - PINCache (>= 3.0.1-beta.3) @@ -124,11 +68,6 @@ PODS: - libwebp/mux (1.2.1): - libwebp/demux - libwebp/webp (1.2.1) - - nanopb (2.30908.0): - - nanopb/decode (= 2.30908.0) - - nanopb/encode (= 2.30908.0) - - nanopb/decode (2.30908.0) - - nanopb/encode (2.30908.0) - path_provider_ios (0.0.1): - Flutter - PINCache (3.0.3): @@ -139,7 +78,6 @@ PODS: - PINCache/Core (3.0.3): - PINOperation (~> 1.2.1) - PINOperation (1.2.1) - - PromisesObjC (2.1.0) - SDWebImage (5.12.5): - SDWebImage/Core (= 5.12.5) - SDWebImage/Core (5.12.5) @@ -161,8 +99,6 @@ DEPENDENCIES: - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - ffmpeg_kit_flutter (from `.symlinks/plugins/ffmpeg_kit_flutter/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) - - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - Flutter (from `Flutter`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - FYVideoCompressor @@ -179,21 +115,12 @@ SPEC REPOS: - DKImagePickerController - DKPhotoGallery - ffmpeg-kit-ios-https - - Firebase - - FirebaseCore - - FirebaseCoreDiagnostics - - FirebaseInstallations - - FirebaseMessaging - FYVideoCompressor - GCDWebServer - - GoogleDataTransport - - GoogleUtilities - HLSCachingReverseProxyServer - libwebp - - nanopb - PINCache - PINOperation - - PromisesObjC - SDWebImage - SwiftyGif @@ -206,10 +133,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/ffmpeg_kit_flutter/ios" file_picker: :path: ".symlinks/plugins/file_picker/ios" - firebase_core: - :path: ".symlinks/plugins/firebase_core/ios" - firebase_messaging: - :path: ".symlinks/plugins/firebase_messaging/ios" Flutter: :path: Flutter flutter_secure_storage: @@ -235,27 +158,16 @@ SPEC CHECKSUMS: DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 ffmpeg-kit-ios-https: cec24d405b511e4f274980d8a9c751d384f89558 ffmpeg_kit_flutter: e2f0bd6b75e361faeee3b34c70650d3ec6ec35d0 - file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 - Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d - firebase_core: fa19947d8db1c0a62d8872c45039b3113829cd2e - firebase_messaging: 943cfe65e0b3f457240489ce67655e40da1d270c - FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1 - FirebaseCoreDiagnostics: 92e07a649aeb66352b319d43bdd2ee3942af84cb - FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd - FirebaseMessaging: 5e5118a2383b3531e730d974680954c679ca0a13 + file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95 Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec FYVideoCompressor: 6d745d0b28432c6abacb234c3c1263755248136b GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4 - GoogleDataTransport: 5fffe35792f8b96ec8d6775f5eccd83c998d5a3b - GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 HLSCachingReverseProxyServer: 59935e1e0244ad7f3375d75b5ef46e8eb26ab181 libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc - nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20 - PromisesObjC: 99b6f43f9e1044bd87a95a60beff28c2c44ddb72 SDWebImage: 0905f1b7760fc8ac4198cae0036600d67478751e share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index 9cb2b878..2923cfcf 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -110,7 +110,7 @@ extension AcelaWebViewController: WKScriptMessageHandler { else { return } debugPrint("Is it valid? \(isValid ? "TRUE" : "FALSE")") debugPrint("Error is \(error)") - postingKeyValidationHandler?(response) + postVideoHandler?(response) default: debugPrint("Do nothing here.") } } diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index f497b583..68c032df 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -126,7 +126,7 @@ var newResult = { type: "postVideo", valid: true, - error: JSON.stringify(result), + error: "success", }; window.webkit.messageHandlers.acela.postMessage(result); // Android.postMessage(JSON.stringify(newResult)); diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart deleted file mode 100644 index 4f166e28..00000000 --- a/lib/firebase_options.dart +++ /dev/null @@ -1,67 +0,0 @@ -// File generated by FlutterFire CLI. -// ignore_for_file: lines_longer_than_80_chars -import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; -import 'package:flutter/foundation.dart' - show defaultTargetPlatform, kIsWeb, TargetPlatform; - -/// Default [FirebaseOptions] for use with your Firebase apps. -/// -/// Example: -/// ```dart -/// import 'firebase_options.dart'; -/// // ... -/// await Firebase.initializeApp( -/// options: DefaultFirebaseOptions.currentPlatform, -/// ); -/// ``` -class DefaultFirebaseOptions { - static FirebaseOptions get currentPlatform { - if (kIsWeb) { - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for web - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); - } - // ignore: missing_enum_constant_in_switch - switch (defaultTargetPlatform) { - case TargetPlatform.android: - return android; - case TargetPlatform.iOS: - return ios; - case TargetPlatform.macOS: - return macos; - } - - throw UnsupportedError( - 'DefaultFirebaseOptions are not supported for this platform.', - ); - } - - static const FirebaseOptions android = FirebaseOptions( - apiKey: 'AIzaSyDZlrKYsD3jlvFkfiXPg3bbVjizqMUqSnE', - appId: '1:252548198943:android:ea163470c7c668c9355b2a', - messagingSenderId: '252548198943', - projectId: 'acela-9c624', - storageBucket: 'acela-9c624.appspot.com', - ); - - static const FirebaseOptions ios = FirebaseOptions( - apiKey: 'AIzaSyBhRRZgrQb8WfCKVMjOwC4jnK0XiMuK4YM', - appId: '1:252548198943:ios:2fcda030e33a7164355b2a', - messagingSenderId: '252548198943', - projectId: 'acela-9c624', - storageBucket: 'acela-9c624.appspot.com', - iosClientId: '252548198943-ec3gnethnkvoudaat0lrobmq2t7mve8g.apps.googleusercontent.com', - iosBundleId: 'com.example.acela', - ); - - static const FirebaseOptions macos = FirebaseOptions( - apiKey: 'AIzaSyBhRRZgrQb8WfCKVMjOwC4jnK0XiMuK4YM', - appId: '1:252548198943:ios:2fcda030e33a7164355b2a', - messagingSenderId: '252548198943', - projectId: 'acela-9c624', - storageBucket: 'acela-9c624.appspot.com', - iosClientId: '252548198943-ec3gnethnkvoudaat0lrobmq2t7mve8g.apps.googleusercontent.com', - iosBundleId: 'com.example.acela', - ); -} diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart index f054dcde..850763b8 100644 --- a/lib/generated_plugin_registrant.dart +++ b/lib/generated_plugin_registrant.dart @@ -5,18 +5,17 @@ // ignore_for_file: directives_ordering // ignore_for_file: lines_longer_than_80_chars -import 'package:firebase_core_web/firebase_core_web.dart'; +// import 'package:firebase_core_web/firebase_core_web.dart'; +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:share_plus_web/share_plus_web.dart'; import 'package:url_launcher_web/url_launcher_web.dart'; import 'package:video_player_web/video_player_web.dart'; import 'package:video_player_web_hls/video_player_web_hls.dart'; import 'package:wakelock_web/wakelock_web.dart'; -import 'package:flutter_web_plugins/flutter_web_plugins.dart'; - // ignore: public_member_api_docs void registerPlugins(Registrar registrar) { - FirebaseCoreWeb.registerWith(registrar); + // FirebaseCoreWeb.registerWith(registrar); SharePlusPlugin.registerWith(registrar); UrlLauncherPlugin.registerWith(registrar); VideoPlayerPlugin.registerWith(registrar); diff --git a/lib/main.dart b/lib/main.dart index 249a57af..dce9c6dc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,16 +1,14 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_messaging/firebase_messaging.dart'; +// import 'package:firebase_core/firebase_core.dart'; +// import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:overlay_support/overlay_support.dart'; import 'package:provider/provider.dart'; -import 'firebase_options.dart'; - class PushNotification { PushNotification({ this.title, @@ -35,7 +33,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { late final Future _futureToLoadData; - late final FirebaseMessaging _messaging; + // late final FirebaseMessaging _messaging; // Create storage Widget futureBuilder(Widget withWidget) { @@ -85,50 +83,50 @@ class _MyAppState extends State { _futureToLoadData = loadData(); } - Future handlingNotification() async { - try { - // 3. On iOS, this helps to take the user permissions - NotificationSettings settings = await _messaging.requestPermission( - alert: true, - badge: false, - provisional: false, - sound: true, - ); - if (settings.authorizationStatus == AuthorizationStatus.authorized) { - print('User granted permission'); - FirebaseMessaging.onMessage.listen((RemoteMessage message) { - // Parse the message received - PushNotification notification = PushNotification( - title: message.notification?.title, - body: message.notification?.body, - ); - - setState(() { - showSimpleNotification( - Text(notification.title ?? "No title for notification"), - // leading: NotificationBadge(totalNotifications: _totalNotifications), - subtitle: Text(notification.body ?? - "No text provided for info of notification"), - background: Colors.cyan.shade700, - duration: Duration(seconds: 2), - ); - }); - }); - } else { - print('User declined or has not accepted permission'); - } - } catch (e) { - print("Something went wrong in setting up fcm ${e.toString()}"); - } - } + // Future handlingNotification() async { + // try { + // // 3. On iOS, this helps to take the user permissions + // NotificationSettings settings = await _messaging.requestPermission( + // alert: true, + // badge: false, + // provisional: false, + // sound: true, + // ); + // if (settings.authorizationStatus == AuthorizationStatus.authorized) { + // print('User granted permission'); + // FirebaseMessaging.onMessage.listen((RemoteMessage message) { + // // Parse the message received + // PushNotification notification = PushNotification( + // title: message.notification?.title, + // body: message.notification?.body, + // ); + // + // setState(() { + // showSimpleNotification( + // Text(notification.title ?? "No title for notification"), + // // leading: NotificationBadge(totalNotifications: _totalNotifications), + // subtitle: Text(notification.body ?? + // "No text provided for info of notification"), + // background: Colors.cyan.shade700, + // duration: Duration(seconds: 2), + // ); + // }); + // }); + // } else { + // print('User declined or has not accepted permission'); + // } + // } catch (e) { + // print("Something went wrong in setting up fcm ${e.toString()}"); + // } + // } Future loadData() async { // setup firebase - await Firebase.initializeApp( - options: DefaultFirebaseOptions.currentPlatform); - _messaging = FirebaseMessaging.instance; + // await Firebase.initializeApp( + // options: DefaultFirebaseOptions.currentPlatform); + // _messaging = FirebaseMessaging.instance; // handle notifications - await handlingNotification(); + // await handlingNotification(); // load storage const storage = FlutterSecureStorage(); String? username = await storage.read(key: 'username'); diff --git a/lib/src/models/login/memo_serializer.dart b/lib/src/models/login/memo_serializer.dart new file mode 100644 index 00000000..7b5fb87a --- /dev/null +++ b/lib/src/models/login/memo_serializer.dart @@ -0,0 +1,7 @@ +// final MemoSerializer = ObjectSerializer({ +// 'ref_block_num': UInt16Serializer(), +// 'ref_block_prefix': UInt32Serializer(), +// 'expiration': DateSerializer(), +// 'operations': ArraySerializer(OperationSerializer()), +// 'extensions': ArraySerializer(StringSerializer()), +// }); diff --git a/lib/src/screens/communities_screen/communities_screen.dart b/lib/src/screens/communities_screen/communities_screen.dart index 45d25767..5e4ebd74 100644 --- a/lib/src/screens/communities_screen/communities_screen.dart +++ b/lib/src/screens/communities_screen/communities_screen.dart @@ -84,7 +84,10 @@ class _CommunitiesScreenState extends State { ); } } else { - return const LoadingScreen(); + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); } }, future: getData()); diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index 3cc84bea..790e7877 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -190,7 +190,10 @@ class _CommunityDetailScreenState extends State List items = snapshot.data! as List; return list(items, _loadHomeFeed, onTap, onUserTap); } else { - return const LoadingScreen(); + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); } }, ); @@ -223,7 +226,10 @@ class _CommunityDetailScreenState extends State snapshot.data! as CommunityDetailsResponse; return _descriptionMarkDown(_generateMarkDown(data)); } else { - return const LoadingScreen(); + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); } }, ); @@ -257,7 +263,10 @@ class _CommunityDetailScreenState extends State itemCount: data.result.team.length, ); } else { - return const LoadingScreen(); + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); } }, ); diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 352bfa42..a503056d 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -13,6 +13,7 @@ import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/utils/crypto_manager.dart'; import 'package:cross_file/cross_file.dart' show XFile; import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; import 'package:ffmpeg_kit_flutter/media_information_session.dart'; @@ -149,6 +150,22 @@ class _HomeScreenState extends State { }, payout); } + Widget _fab2(HiveUserData user) { + if (isFabLoading) { + return FloatingActionButton( + onPressed: () {}, child: const CircularProgressIndicator()); + } + return FloatingActionButton( + onPressed: () { + var text = + "#28A2K2zxWrh1n6oEm6tq5mgascootxuDHaGEAXEN86ZHpiGRhgnSUN2Xm2FgtUnq82QtLybJKtProLeJdntA3LCL2J9SAnfru965mbC8D3XZZKgx1vXP8osxvLuPCqhUW6xZZQ3J5mixDwtwLwPdtYcxRTbHtL66H9jDK1C1Q5wyR4F21K3SihJGeacM63eUceW1ThK8kV9Pv24eMnv3aD2oQgrJywNgqZqNH7GcAnYh4wnytMNkDKyy2h5ApUhmBkfqKjgmEWm5ngxBgn1jpaxxmN8guJgRkB1HSgAdM29MQSgPoXHUJ8hkf9jkRXyz6TW7W45PsboBWi1xs1nu3xwySKq4BxxetQzNRHkRiudQ2HDQCWKJNFJieFpVq1M1qUVbMqUuAyaxKcAAroCJbdvEnUvcfh4"; + var data = CryptoManager().decodeMemo(text, user.postingKey); + print("Data is $data"); + }, + child: const Icon(Icons.bolt), + ); + } + Widget _fab(HiveUserData user) { if (isFabLoading) { return FloatingActionButton( diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index 7170b5ce..ca78b332 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -8,7 +8,10 @@ import 'package:timeago/timeago.dart' as timeago; class HomeScreenWidgets { Widget loadingData() { - return const LoadingScreen(); + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); } Widget _tileTitle( diff --git a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart index a8217760..8bc06eaa 100644 --- a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart +++ b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart @@ -121,7 +121,10 @@ class _LeaderboardScreenState extends State { ); } } else { - return const LoadingScreen(); + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); } }, future: getData()); diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 834c7c88..f7d9f321 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -1,7 +1,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; -import 'package:acela/src/utils/priv_to_pub.dart'; +import 'package:acela/src/utils/crypto_manager.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index 8c4df129..71c1397f 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -1,5 +1,4 @@ import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/screens/my_account/account_settings/manage_notifications.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:provider/provider.dart'; @@ -44,15 +43,15 @@ class _AccountSettingsScreenState extends State { body: SafeArea( child: ListView( children: [ - ListTile( - leading: const Icon(Icons.notifications), - title: const Text('Manage Notifications'), - onTap: () { - var screen = ManageNotificationsScreen(); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - ), + // ListTile( + // leading: const Icon(Icons.notifications), + // title: const Text('Manage Notifications'), + // onTap: () { + // var screen = ManageNotificationsScreen(); + // var route = MaterialPageRoute(builder: (c) => screen); + // Navigator.of(context).push(route); + // }, + // ), _changeTheme(context), ListTile( leading: const Icon(Icons.logout), diff --git a/lib/src/screens/my_account/account_settings/manage_notifications.dart b/lib/src/screens/my_account/account_settings/manage_notifications.dart index 12b05595..79eb9c9b 100644 --- a/lib/src/screens/my_account/account_settings/manage_notifications.dart +++ b/lib/src/screens/my_account/account_settings/manage_notifications.dart @@ -1,12 +1,8 @@ -import 'dart:developer'; -import 'dart:io'; - import 'package:acela/src/models/my_account/my_devices.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/loading_screen.dart'; -import 'package:device_info_plus/device_info_plus.dart'; -import 'package:firebase_messaging/firebase_messaging.dart'; +// import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -88,42 +84,45 @@ class _ManageNotificationsScreenState extends State { snapshot.connectionState == ConnectionState.done) { return _deviceList(snapshot.data as List, user); } else { - return const LoadingScreen(); + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); } }, ); } - void registerForNotification(HiveUserData user) async { - setState(() { - isDeletingOrSending = true; - }); - try { - final fcmToken = await FirebaseMessaging.instance.getToken(); - var model = ''; - DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); - if (Platform.isAndroid) { - AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; - print('Running on ${androidInfo.model}'); - model = androidInfo.model ?? 'Some Android Device'; - } else if (Platform.isIOS) { - IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo; - print('Running on ${iosDeviceInfo.model}'); - model = iosDeviceInfo.model ?? 'Some iOS Device'; - } else { - model = 'Unknown Device type'; - } - log('FCM Token is $fcmToken'); - await Communicator().addToken(user, fcmToken ?? "", model); - } catch (e) { - showError("Something went wrong\n${e.toString()}"); - } finally { - setState(() { - isDeletingOrSending = false; - getDevices = null; - }); - } - } + // void registerForNotification(HiveUserData user) async { + // setState(() { + // isDeletingOrSending = true; + // }); + // try { + // final fcmToken = await FirebaseMessaging.instance.getToken(); + // var model = ''; + // DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); + // if (Platform.isAndroid) { + // AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; + // print('Running on ${androidInfo.model}'); + // model = androidInfo.model ?? 'Some Android Device'; + // } else if (Platform.isIOS) { + // IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo; + // print('Running on ${iosDeviceInfo.model}'); + // model = iosDeviceInfo.model ?? 'Some iOS Device'; + // } else { + // model = 'Unknown Device type'; + // } + // log('FCM Token is $fcmToken'); + // await Communicator().addToken(user, fcmToken ?? "", model); + // } catch (e) { + // showError("Something went wrong\n${e.toString()}"); + // } finally { + // setState(() { + // isDeletingOrSending = false; + // getDevices = null; + // }); + // } + // } void sendTestNotification(HiveUserData user) async { // testTokens @@ -164,21 +163,27 @@ class _ManageNotificationsScreenState extends State { title: const Text('Manage Notifications'), actions: isDeletingOrSending ? [] - : [IconButton(onPressed: () {sendTestNotification(user);}, icon: Icon(Icons.notifications))], + : [ + IconButton( + onPressed: () { + sendTestNotification(user); + }, + icon: Icon(Icons.notifications)) + ], ), body: SafeArea( child: isDeletingOrSending ? const Center(child: CircularProgressIndicator()) : _futureForDevices(user), ), - floatingActionButton: isDeletingOrSending - ? null - : FloatingActionButton( - onPressed: () { - registerForNotification(user); - }, - child: const Icon(Icons.add), - ), + // floatingActionButton: isDeletingOrSending + // ? null + // : FloatingActionButton( + // onPressed: () { + // registerForNotification(user); + // }, + // child: const Icon(Icons.add), + // ), ); } } diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 5e63cd92..d9dfe45b 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -25,6 +25,7 @@ class _MyAccountScreenState extends State { Future>? loadVideos; Future? loadOperations; var isLoading = false; + var loadingText = ''; void logout() async { // Create storage @@ -38,11 +39,15 @@ class _MyAccountScreenState extends State { void loadVideoInfo(HiveUserData user, String videoId) async { setState(() { isLoading = true; + loadingText = 'Getting video data to post on Hive'; }); try { var result = await Communicator().loadOperations(user, videoId); var utf8data = utf8.encode(result); final base64Str = base64.encode(utf8data); + setState(() { + loadingText = 'Publishing on Hive'; + }); var platform = MethodChannel('com.example.acela/auth'); final String response = await platform.invokeMethod('postVideo', { 'data': base64Str, @@ -50,8 +55,12 @@ class _MyAccountScreenState extends State { }); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); if (bridgeResponse.valid == true) { + setState(() { + loadingText = 'Marking video as published'; + }); await Communicator().updatePublishState(user, videoId); setState(() { + isLoading = false; loadVideos = Communicator().loadVideos(user); }); } else { @@ -153,7 +162,10 @@ class _MyAccountScreenState extends State { snapshot.connectionState == ConnectionState.done) { return _videosList(snapshot.data as List, user); } else { - return const LoadingScreen(); + return const LoadingScreen( + title: 'Getting your videos', + subtitle: 'Please wait', + ); } }, ); @@ -174,7 +186,12 @@ class _MyAccountScreenState extends State { child: user == null ? Center(child: const Text('Nothing')) : isLoading - ? Center(child: const CircularProgressIndicator()) + ? Center( + child: LoadingScreen( + title: 'Publishing Your Video', + subtitle: loadingText, + ), + ) : _videoFuture(user), ), ); diff --git a/lib/src/screens/upload/upload_extra_screen.dart b/lib/src/screens/upload/upload_extra_screen.dart index 42499168..0783576b 100644 --- a/lib/src/screens/upload/upload_extra_screen.dart +++ b/lib/src/screens/upload/upload_extra_screen.dart @@ -1,5 +1,6 @@ import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; import 'package:cross_file/cross_file.dart' show XFile; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; @@ -36,6 +37,7 @@ class _UploadExtraScreenState extends State { var thumbUrl = ''; var tags = ''; var progress = 0.0; + var processText = ''; void showError(String string) { var snackBar = SnackBar(content: Text('Error: $string')); @@ -85,6 +87,7 @@ class _UploadExtraScreenState extends State { void completeVideo(HiveUserData user) async { setState(() { isCompleting = true; + processText = 'Updating video info'; }); try { var videoUploadInfo = await Communicator().uploadComplete( @@ -101,6 +104,7 @@ class _UploadExtraScreenState extends State { showMessage('Video is uploaded & moved to encoding queue'); setState(() { isCompleting = false; + processText = ''; }); Navigator.of(context).pop(); Navigator.of(context).pop(); @@ -222,7 +226,12 @@ class _UploadExtraScreenState extends State { title: const Text('Provide more info'), ), body: isCompleting - ? const Center(child: CircularProgressIndicator()) + ? Center( + child: LoadingScreen( + title: 'Please wait', + subtitle: processText, + ), + ) : Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ diff --git a/lib/src/screens/user_channel_screen/user_channel_following.dart b/lib/src/screens/user_channel_screen/user_channel_following.dart index c05e5777..fed3af34 100644 --- a/lib/src/screens/user_channel_screen/user_channel_following.dart +++ b/lib/src/screens/user_channel_screen/user_channel_following.dart @@ -67,7 +67,10 @@ class _UserChannelFollowingWidgetState extends State itemCount: data.result.length, ); } else { - return const LoadingScreen(); + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); } }, ); diff --git a/lib/src/screens/user_channel_screen/user_channel_profile.dart b/lib/src/screens/user_channel_screen/user_channel_profile.dart index 6de0fecb..cb291ffd 100644 --- a/lib/src/screens/user_channel_screen/user_channel_profile.dart +++ b/lib/src/screens/user_channel_screen/user_channel_profile.dart @@ -73,7 +73,10 @@ class _UserChannelProfileWidgetState extends State var data = snapshot.data! as UserProfileResponse; return _descriptionMarkDown(_generateMarkDown(data)); } else { - return const LoadingScreen(); + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); } }, ); diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart index 46c9e73f..9607dd35 100644 --- a/lib/src/screens/user_channel_screen/user_channel_videos.dart +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -163,7 +163,10 @@ class UserChannelVideosState extends State Widget _futureVideos() { if (isLoading) { - return const LoadingScreen(); + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); } if (list.isEmpty) { return Center(child: const Text('No videos found.')); diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 6f452064..3d24bed4 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -440,7 +440,13 @@ class _VideoDetailsScreenState extends State { ); } } else { - return container(widget.vm.author, const LoadingScreen()); + return container( + widget.vm.author, + const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ), + ); } }, ); diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index f0b95035..12a7d361 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -19,16 +19,16 @@ import 'package:http/http.dart' as http; class Communicator { // Production - // static const tsServer = "https://studio.3speak.tv"; - // static const fsServer = "https://uploads.3speak.tv/files"; + static const tsServer = "https://studio.3speak.tv"; + static const fsServer = "https://uploads.3speak.tv/files"; // Android // static const fsServer = "http://10.0.2.2:1080/files"; // static const tsServer = "http://10.0.2.2:13050"; // iOS - static const tsServer = "http://localhost:13050"; - static const fsServer = "http://localhost:1080/files"; + // static const tsServer = "http://localhost:13050"; + // static const fsServer = "http://localhost:1080/files"; static const hiveApiUrl = 'https://api.hive.blog/'; @@ -314,6 +314,7 @@ class Communicator { } Future> loadVideos(HiveUserData user) async { + print("Starting fetch videos ${DateTime.now().toIso8601String()}"); var cookie = await getValidCookie(user); var request = http.Request( 'GET', Uri.parse('${Communicator.tsServer}/mobile/api/my-videos')); @@ -323,6 +324,7 @@ class Communicator { if (response.statusCode == 200) { var string = await response.stream.bytesToString(); var videos = videoItemsFromString(string); + print("Ended fetch videos ${DateTime.now().toIso8601String()}"); return videos; } else { var string = await response.stream.bytesToString(); diff --git a/lib/src/utils/crypto_manager.dart b/lib/src/utils/crypto_manager.dart new file mode 100644 index 00000000..0b40e673 --- /dev/null +++ b/lib/src/utils/crypto_manager.dart @@ -0,0 +1,21 @@ +// import 'package:bs58/bs58.dart'; +// import 'package:elliptic/elliptic.dart'; +import 'package:bs58check/bs58check.dart' as bs58check; +import 'package:hex/hex.dart'; +import 'package:steemdart_ecc/steemdart_ecc.dart'; + +class CryptoManager { + String privToPub(String privateKey) { + SteemPrivateKey pkey = SteemPrivateKey.fromString(privateKey); + return pkey.toPublicKey().toString(); + } + + String decodeMemo(String memo, String privateKey) { + SteemPrivateKey pkey = SteemPrivateKey.fromString(privateKey); + SteemPublicKey publicKey = pkey.toPublicKey(); + var newMemo = memo.replaceAll("#", ""); + var decodedMemo = bs58check.base58.decode(newMemo); + var hexString = HEX.encode(decodedMemo); + return hexString; + } +} diff --git a/lib/src/utils/priv_to_pub.dart b/lib/src/utils/priv_to_pub.dart deleted file mode 100644 index 0acfb142..00000000 --- a/lib/src/utils/priv_to_pub.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:steemdart_ecc/steemdart_ecc.dart'; - -class CryptoManager { - String privToPub(String privateKey) { - SteemPrivateKey pkey = SteemPrivateKey.fromString(privateKey); - return pkey.toPublicKey().toString(); - } -} diff --git a/lib/src/widgets/loading_screen.dart b/lib/src/widgets/loading_screen.dart index 2742f840..f2800b5c 100644 --- a/lib/src/widgets/loading_screen.dart +++ b/lib/src/widgets/loading_screen.dart @@ -1,7 +1,10 @@ import 'package:flutter/material.dart'; class LoadingScreen extends StatelessWidget { - const LoadingScreen({Key? key}) : super(key: key); + const LoadingScreen({Key? key, required this.title, required this.subtitle}) + : super(key: key); + final String title; + final String subtitle; @override Widget build(BuildContext context) { @@ -9,14 +12,26 @@ class LoadingScreen extends StatelessWidget { child: Column( children: [ const Spacer(), - const CircularProgressIndicator(value: null,), - const SizedBox(height: 20,), - Text('Loading Data', style: Theme.of(context).textTheme.bodyText1,), - const SizedBox(height: 10,), - Text('Please wait', style: Theme.of(context).textTheme.bodyText2,), + const CircularProgressIndicator( + value: null, + ), + const SizedBox( + height: 20, + ), + Text( + title, + style: Theme.of(context).textTheme.bodyText1, + ), + const SizedBox( + height: 10, + ), + Text( + subtitle, + style: Theme.of(context).textTheme.bodyText2, + ), const Spacer(), ], ), ); } -} \ No newline at end of file +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index da2a14b4..0f9ac75f 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,8 +7,6 @@ import Foundation import device_info_plus_macos import ffmpeg_kit_flutter -import firebase_core -import firebase_messaging import flutter_secure_storage_macos import path_provider_macos import share_plus_macos @@ -18,8 +16,6 @@ import wakelock_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin")) - FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) - FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) FlutterSecureStorageMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageMacosPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) diff --git a/pubspec.lock b/pubspec.lock index e6a04321..e7f4dc86 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,7 +7,7 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "41.0.0" + version: "42.0.0" adaptive_action_sheet: dependency: "direct main" description: @@ -21,7 +21,7 @@ packages: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "4.2.0" + version: "4.3.0" args: dependency: transitive description: @@ -316,48 +316,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.6.1" - firebase_core: - dependency: "direct main" - description: - name: firebase_core - url: "https://pub.dartlang.org" - source: hosted - version: "1.20.0" - firebase_core_platform_interface: - dependency: transitive - description: - name: firebase_core_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "4.5.0" - firebase_core_web: - dependency: transitive - description: - name: firebase_core_web - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.1" - firebase_messaging: - dependency: "direct main" - description: - name: firebase_messaging - url: "https://pub.dartlang.org" - source: hosted - version: "11.4.4" - firebase_messaging_platform_interface: - dependency: transitive - description: - name: firebase_messaging_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "3.5.4" - firebase_messaging_web: - dependency: transitive - description: - name: firebase_messaging_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.4.4" fixnum: dependency: transitive description: @@ -1016,7 +974,7 @@ packages: name: video_player_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.12" video_player_web_hls: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 27171534..81339605 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,8 +37,6 @@ dependencies: elliptic: ^0.3.8 ffmpeg_kit_flutter: ^4.5.1 file_picker: ^4.5.1 - firebase_core: ^1.12.0 - firebase_messaging: ^11.4.1 flutter: sdk: flutter flutter_dotenv: ^5.0.2 From 52ca7c40f637e759106104fadc80ff8648cb8d45 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sat, 23 Jul 2022 20:13:25 +0530 Subject: [PATCH 096/466] version bump. --- .flutter-plugins-dependencies | 2 +- .packages | 2 +- pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index e6b77d46..9acacc3b 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-23 18:49:33.866142","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-23 20:13:07.396847","version":"3.0.4"} \ No newline at end of file diff --git a/.packages b/.packages index cc349521..a355b8b7 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-07-23 08:25:31.906225. +# Generated by pub on 2022-07-23 20:13:07.231188. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-42.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.2/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.3.0/lib/ diff --git a/pubspec.yaml b/pubspec.yaml index 81339605..e1d2a380 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.1+23 +version: 1.0.1+24 environment: sdk: ">=2.15.1 <3.0.0" From 6e6b92b19a8593aa49b9ceb75fee36a63aacb28d Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 24 Jul 2022 22:13:30 +0530 Subject: [PATCH 097/466] updated depenc --- .flutter-plugins-dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 9acacc3b..54494cd1 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-23 20:13:07.396847","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-23 20:22:15.949821","version":"3.0.4"} \ No newline at end of file From 5c43f93c0bdbcc957809ddd260745efc0cf3996d Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 24 Jul 2022 22:34:03 +0530 Subject: [PATCH 098/466] version bump --- .DS_Store | Bin 6148 -> 6148 bytes .flutter-plugins-dependencies | 2 +- .packages | 2 +- ios/Runner/Info.plist | 4 ++-- pubspec.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.DS_Store b/.DS_Store index aa38b5f10ddb820cfa227fe34955814c679270da..cf4c1241139d373936b1d597d5d7a788f00dbcac 100644 GIT binary patch delta 145 zcmZoMXfc=|#>B)qu~2NHo}w@d0|Nsi1A_nqLrPM4aY0f}e$wWTj4K)WK@zMCNerb7 znG87$DU-z*8$?VjEp-%3jLmCx6sj$a41jD)qsglnjm41^mIW8(<>cq3gUsE`!^qFN fnVo~5185=8*ze4f`9&-_fc60q1HB`mu~2NHo}wrd0|Nsi1A_oVaY0f}eiD$kBdK6w;qu7_A}pJKGx4x) l{=oc(aWgvyKL=3L=7-GRnJ4p$SaJXrg7h(M4iMSG3;?8>6CFBundlePackageType APPL CFBundleShortVersionString - $(MARKETING_VERSION) + $(FLUTTER_BUILD_NAME) CFBundleSignature ???? CFBundleVersion - $(CURRENT_PROJECT_VERSION) + $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS LSSupportsOpeningDocumentsInPlace diff --git a/pubspec.yaml b/pubspec.yaml index e1d2a380..b90fcab0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.1+24 +version: 1.0.1+25 environment: sdk: ">=2.15.1 <3.0.0" From 901c24d9a1f6be367f31e6a7cc1783aa75003ad3 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 24 Jul 2022 22:35:10 +0530 Subject: [PATCH 099/466] updated gitignore --- ios/.gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ios/.gitignore b/ios/.gitignore index 7a7f9873..c65d6368 100644 --- a/ios/.gitignore +++ b/ios/.gitignore @@ -1,3 +1,7 @@ +fastlane +*.ipa +*.app.dSYM.zip + **/dgph *.mode1v3 *.mode2v3 @@ -31,4 +35,4 @@ Runner/GeneratedPluginRegistrant.* !default.mode1v3 !default.mode2v3 !default.pbxuser -!default.perspectivev3 +!default.perspectivev3 \ No newline at end of file From 8569baff6a42f29a8b0ba58f677d9bdb7f6bd15b Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 24 Jul 2022 22:38:25 +0530 Subject: [PATCH 100/466] setting up fastlane --- ios/Gemfile | 6 + ios/Gemfile.lock | 218 +++++++++++++++++++++++++++ ios/Runner.xcodeproj/project.pbxproj | 7 + 3 files changed, 231 insertions(+) create mode 100644 ios/Gemfile create mode 100644 ios/Gemfile.lock diff --git a/ios/Gemfile b/ios/Gemfile new file mode 100644 index 00000000..d554c27a --- /dev/null +++ b/ios/Gemfile @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gem "fastlane" +# gem "rails" diff --git a/ios/Gemfile.lock b/ios/Gemfile.lock new file mode 100644 index 00000000..74cafaff --- /dev/null +++ b/ios/Gemfile.lock @@ -0,0 +1,218 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.5) + rexml + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + artifactory (3.0.15) + atomos (0.1.3) + aws-eventstream (1.2.0) + aws-partitions (1.610.0) + aws-sdk-core (3.131.3) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.525.0) + aws-sigv4 (~> 1.1) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.58.0) + aws-sdk-core (~> 3, >= 3.127.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.114.0) + aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.4) + aws-sigv4 (1.5.1) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + declarative (0.0.20) + digest-crc (0.6.4) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.7.6) + emoji_regex (3.2.3) + excon (0.92.4) + faraday (1.10.0) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) + http-cookie (~> 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + fastimage (2.2.6) + fastlane (2.208.0) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander (~> 4.6) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (~> 2.0.0) + naturally (~> 2.2) + optparse (~> 0.1.1) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.25.0) + google-apis-core (>= 0.7, < 2.a) + google-apis-core (0.7.0) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.13.0) + google-apis-core (>= 0.7, < 2.a) + google-apis-playcustomapp_v1 (0.10.0) + google-apis-core (>= 0.7, < 2.a) + google-apis-storage_v1 (0.18.0) + google-apis-core (>= 0.7, < 2.a) + google-cloud-core (1.6.0) + google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.2.0) + google-cloud-storage (1.37.0) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.1) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) + mini_mime (~> 1.0) + googleauth (1.2.0) + faraday (>= 0.17.3, < 3.a) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.5) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.6.1) + json (2.6.2) + jwt (2.4.1) + memoist (0.16.2) + mini_magick (4.11.0) + mini_mime (1.1.2) + multi_json (1.15.0) + multipart-post (2.0.0) + nanaimo (0.3.0) + naturally (2.2.1) + optparse (0.1.1) + os (1.1.4) + plist (3.6.0) + public_suffix (4.0.7) + rake (13.0.6) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rexml (3.2.5) + rouge (2.0.7) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + security (0.1.3) + signet (0.17.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.8) + CFPropertyList + naturally + terminal-notifier (2.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) + webrick (1.7.0) + word_wrap (1.0.0) + xcodeproj (1.22.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + arm64-darwin-21 + +DEPENDENCIES + fastlane + +BUNDLED WITH + 2.3.14 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index fb401383..028ac3fc 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -421,6 +421,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 23; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; @@ -433,6 +435,7 @@ MARKETING_VERSION = 1.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.example.acela"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -561,6 +564,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 23; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; @@ -573,6 +577,7 @@ MARKETING_VERSION = 1.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "match Development com.example.acela"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -587,6 +592,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 23; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; @@ -599,6 +605,7 @@ MARKETING_VERSION = 1.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "match Development com.example.acela"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; From 9eed5c827a05ee40a45a5fa7a4acf0ef47297b8d Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 24 Jul 2022 22:54:08 +0530 Subject: [PATCH 101/466] correction in cert --- .flutter-plugins-dependencies | 2 +- ios/Runner.xcodeproj/project.pbxproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index d573bb47..069a483f 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-24 22:14:04.754428","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-24 22:38:41.992248","version":"3.0.4"} \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 028ac3fc..e9a4fcc4 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -605,7 +605,7 @@ MARKETING_VERSION = 1.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.example.acela; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match Development com.example.acela"; + PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.example.acela"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; From b266f92d9e7aac4bdb8a4a7d98d4935e844b6dd3 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 24 Jul 2022 22:55:25 +0530 Subject: [PATCH 102/466] correction in cert --- ios/Runner.xcodeproj/project.pbxproj | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index e9a4fcc4..9216a294 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -421,7 +421,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution"; + CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 23; DEVELOPMENT_TEAM = 58LRY57FMK; @@ -564,6 +565,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_IDENTITY = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 23; DEVELOPMENT_TEAM = 58LRY57FMK; @@ -592,6 +595,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 23; DEVELOPMENT_TEAM = 58LRY57FMK; From 949feb2a19eb93878e79b441eab11b7884ee609c Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 5 Aug 2022 03:14:15 +0530 Subject: [PATCH 103/466] new video compression logic. --- .flutter-plugins | 8 +- .flutter-plugins-dependencies | 2 +- .idea/Android-App.iml | 6 + .idea/libraries/Dart_Packages.xml | 64 ++++-- .idea/libraries/Flutter_Plugins.xml | 8 +- .packages | 19 +- ios/Podfile.lock | 12 ++ .../screens/drawer_screen/drawer_screen.dart | 2 + lib/src/screens/home_screen/home_screen.dart | 72 ++++--- lib/src/screens/login/new_login_screen.dart | 38 ++++ .../login/webview/navigation_controls.dart | 67 +++++++ .../screens/login/webview/webview_stack.dart | 52 +++++ .../screens/my_account/my_account_screen.dart | 4 +- .../upload/new_video_upload_screen.dart | 188 ++++++++++++++++++ lib/src/utils/communicator.dart | 8 +- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 47 ++++- pubspec.yaml | 2 + 18 files changed, 535 insertions(+), 66 deletions(-) create mode 100644 lib/src/screens/login/new_login_screen.dart create mode 100644 lib/src/screens/login/webview/navigation_controls.dart create mode 100644 lib/src/screens/login/webview/webview_stack.dart create mode 100644 lib/src/screens/upload/new_video_upload_screen.dart diff --git a/.flutter-plugins b/.flutter-plugins index 49982c00..1b043259 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -14,8 +14,8 @@ flutter_secure_storage_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub flutter_secure_storage_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/ flutter_secure_storage_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/ path_provider=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.11/ -path_provider_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/ -path_provider_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/ +path_provider_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/ +path_provider_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/ path_provider_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/ path_provider_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/ path_provider_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/ @@ -31,6 +31,7 @@ url_launcher_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang. url_launcher_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/ url_launcher_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/ url_launcher_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/ +video_compress=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/ video_player=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.4.5/ video_player_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/ video_player_avfoundation=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/ @@ -40,3 +41,6 @@ video_thumbnail=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org wakelock=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/ wakelock_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/ wakelock_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/ +webview_flutter=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter-3.0.4/ +webview_flutter_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/ +webview_flutter_wkwebview=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 069a483f..00ba147f 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]}],"date_created":"2022-07-24 22:38:41.992248","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-05 03:07:49.835916","version":"3.0.4"} \ No newline at end of file diff --git a/.idea/Android-App.iml b/.idea/Android-App.iml index 9caeb157..64138120 100644 --- a/.idea/Android-App.iml +++ b/.idea/Android-App.iml @@ -86,6 +86,12 @@ + + + + + + diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 9c1d0cde..cc4f6608 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -5,7 +5,7 @@ - @@ -19,7 +19,7 @@ - @@ -173,7 +173,7 @@ - @@ -614,14 +614,14 @@ - - @@ -761,7 +761,7 @@ - @@ -947,6 +947,13 @@ + + + + + + @@ -1052,6 +1059,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -1084,9 +1119,9 @@ - + - + @@ -1108,7 +1143,7 @@ - + @@ -1168,8 +1203,8 @@ - - + + @@ -1189,7 +1224,7 @@ - + @@ -1214,6 +1249,7 @@ + @@ -1229,6 +1265,10 @@ + + + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index b2d8c2e2..37e8f26e 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -25,12 +25,10 @@ - - @@ -38,6 +36,12 @@ + + + + + + diff --git a/.packages b/.packages index dc899073..791d5a80 100644 --- a/.packages +++ b/.packages @@ -3,10 +3,10 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-07-24 22:14:04.517268. -_fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-42.0.0/lib/ +# Generated by pub on 2022-08-05 01:54:35.079798. +_fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-43.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.2/lib/ -analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.3.0/lib/ +analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.3.1/lib/ args:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.3.1/lib/ async:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/ base_x:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/base_x-2.0.0/lib/ @@ -28,7 +28,7 @@ charcode:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org checked_yaml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/checked_yaml-2.0.1/lib/ chewie:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/chewie-1.3.4/lib/ clock:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib/ -code_builder:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/code_builder-4.1.0/lib/ +code_builder:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/code_builder-4.2.0/lib/ collection:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.16.0/lib/ convert:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/convert-3.0.2/lib/ cross_file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/cross_file-0.3.3+1/lib/ @@ -91,8 +91,8 @@ overlay_support:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartl package_config:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_config-2.1.0/lib/ path:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.1/lib/ path_provider:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.11/lib/ -path_provider_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.16/lib/ -path_provider_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.10/lib/ +path_provider_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/lib/ +path_provider_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/lib/ path_provider_linux:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/lib/ path_provider_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/lib/ path_provider_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_platform_interface-2.0.4/lib/ @@ -112,7 +112,7 @@ share_plus_macos:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dart share_plus_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_platform_interface-3.0.3/lib/ share_plus_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/lib/ share_plus_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/lib/ -shelf:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.3.1/lib/ +shelf:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.3.2/lib/ shelf_web_socket:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-1.0.2/lib/ sky_engine:file:///Applications/flutter/flutter/bin/cache/pkg/sky_engine/lib/ source_gen:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/source_gen-1.2.2/lib/ @@ -139,6 +139,7 @@ url_launcher_platform_interface:file:///Applications/flutter/flutter/.pub-cache/ url_launcher_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/lib/ url_launcher_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/lib/ vector_math:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.2/lib/ +video_compress:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/lib/ video_player:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player-2.4.5/lib/ video_player_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/lib/ video_player_avfoundation:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/lib/ @@ -154,6 +155,10 @@ wakelock_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang wakelock_windows:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_windows-0.2.0/lib/ watcher:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/watcher-1.0.1/lib/ web_socket_channel:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.2.0/lib/ +webview_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter-3.0.4/lib/ +webview_flutter_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/lib/ +webview_flutter_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_platform_interface-1.9.1/lib/ +webview_flutter_wkwebview:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/lib/ win32:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/win32-2.6.1/lib/ xdg_directories:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/xdg_directories-0.2.0+1/lib/ xml:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/xml-6.1.0/lib/ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4deb4679..481e00b8 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -86,6 +86,8 @@ PODS: - SwiftyGif (5.4.3) - url_launcher_ios (0.0.1): - Flutter + - video_compress (0.3.0): + - Flutter - video_player_avfoundation (0.0.1): - Flutter - video_thumbnail (0.0.1): @@ -93,6 +95,8 @@ PODS: - libwebp - wakelock (0.0.1): - Flutter + - webview_flutter_wkwebview (0.0.1): + - Flutter DEPENDENCIES: - better_player (from `.symlinks/plugins/better_player/ios`) @@ -105,9 +109,11 @@ DEPENDENCIES: - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + - video_compress (from `.symlinks/plugins/video_compress/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) - video_thumbnail (from `.symlinks/plugins/video_thumbnail/ios`) - wakelock (from `.symlinks/plugins/wakelock/ios`) + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) SPEC REPOS: trunk: @@ -143,12 +149,16 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/share_plus/ios" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" + video_compress: + :path: ".symlinks/plugins/video_compress/ios" video_player_avfoundation: :path: ".symlinks/plugins/video_player_avfoundation/ios" video_thumbnail: :path: ".symlinks/plugins/video_thumbnail/ios" wakelock: :path: ".symlinks/plugins/wakelock/ios" + webview_flutter_wkwebview: + :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" SPEC CHECKSUMS: better_player: 2406bfe8175203c7a46fa15f9d778d73b12e1646 @@ -172,9 +182,11 @@ SPEC CHECKSUMS: share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de + video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1 wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f + webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f PODFILE CHECKSUM: c47b194cb97680e602c9d704f278cff245139eb7 diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 1fa4ee2a..60706abe 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -137,6 +137,8 @@ class DrawerScreen extends StatelessWidget { title: const Text("Log in"), onTap: () { Navigator.pop(context); + // Navigator.of(context) + // .push(MaterialPageRoute(builder: (c) => const NewLoginScreen())); Navigator.of(context) .push(MaterialPageRoute(builder: (c) => const LoginScreen())); }, diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index a503056d..b608ba0c 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -8,12 +8,12 @@ import 'package:acela/src/models/video_upload/platform_video_info.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; import 'package:acela/src/screens/search/search_screen.dart'; +import 'package:acela/src/screens/upload/new_video_upload_screen.dart'; import 'package:acela/src/screens/upload/upload_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/communicator.dart'; -import 'package:acela/src/utils/crypto_manager.dart'; import 'package:cross_file/cross_file.dart' show XFile; import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; import 'package:ffmpeg_kit_flutter/media_information_session.dart'; @@ -21,6 +21,7 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' show get; import 'package:provider/provider.dart'; +import 'package:video_compress/video_compress.dart'; class HomeScreen extends StatefulWidget { const HomeScreen( @@ -150,19 +151,14 @@ class _HomeScreenState extends State { }, payout); } - Widget _fab2(HiveUserData user) { - if (isFabLoading) { - return FloatingActionButton( - onPressed: () {}, child: const CircularProgressIndicator()); - } + Widget _fabNewUpload() { return FloatingActionButton( onPressed: () { - var text = - "#28A2K2zxWrh1n6oEm6tq5mgascootxuDHaGEAXEN86ZHpiGRhgnSUN2Xm2FgtUnq82QtLybJKtProLeJdntA3LCL2J9SAnfru965mbC8D3XZZKgx1vXP8osxvLuPCqhUW6xZZQ3J5mixDwtwLwPdtYcxRTbHtL66H9jDK1C1Q5wyR4F21K3SihJGeacM63eUceW1ThK8kV9Pv24eMnv3aD2oQgrJywNgqZqNH7GcAnYh4wnytMNkDKyy2h5ApUhmBkfqKjgmEWm5ngxBgn1jpaxxmN8guJgRkB1HSgAdM29MQSgPoXHUJ8hkf9jkRXyz6TW7W45PsboBWi1xs1nu3xwySKq4BxxetQzNRHkRiudQ2HDQCWKJNFJieFpVq1M1qUVbMqUuAyaxKcAAroCJbdvEnUvcfh4"; - var data = CryptoManager().decodeMemo(text, user.postingKey); - print("Data is $data"); + var screen = const NewVideoUploadScreen(); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); }, - child: const Icon(Icons.bolt), + child: const Icon(Icons.add), ); } @@ -187,19 +183,34 @@ class _HomeScreenState extends State { print(file.size); print(file.extension); print(file.path); + final compressInfo = await VideoCompress.compressVideo( + file.path!, + quality: VideoQuality.Res1280x720Quality, + deleteOrigin: false, + includeAudio: true, + ); + var fileSize = compressInfo?.filesize ?? file.size; + var sizeInMb = fileSize / 1000 / 1000; + if (sizeInMb > 500) { + throw 'Video is too big to be uploaded from mobile (exceeding 500 mb)'; + } MediaInformationSession session = - await FFprobeKit.getMediaInformation(file.path!); + await FFprobeKit.getMediaInformation( + compressInfo?.file?.path ?? file.path!); var info = session.getMediaInformation(); var duration = (double.tryParse(info?.getDuration() ?? "0.0") ?? 0.0).toInt(); log('Video duration is $duration'); - final xfile = XFile(fileResult.files.single.path!); + final xfile = XFile( + compressInfo?.file?.path ?? fileResult.files.single.path!); var fileInfoInString = json.encode(PlatformVideoInfo( duration: int.tryParse(info?.getDuration() ?? "0") ?? 0, oFilename: xfile.name, path: xfile.path, - size: int.tryParse(info?.getSize() ?? "0") ?? 0) + size: fileSize) .toJson()); + // change from here. + throw 'compression done'; var cookie = await Communicator().getValidCookie(user); log('Cookie is $cookie'); var response = await Communicator() @@ -231,21 +242,22 @@ class _HomeScreenState extends State { Widget build(BuildContext context) { var user = Provider.of(context); return Scaffold( - appBar: AppBar( - title: Text(widget.title), - actions: [ - IconButton( - onPressed: () { - var route = MaterialPageRoute( - builder: (context) => const SearchScreen()); - Navigator.of(context).push(route); - }, - icon: const Icon(Icons.search)) - ], - ), - body: _screen(), - drawer: widget.showDrawer ? const DrawerScreen() : null, - floatingActionButton: user == null ? null : _fab(user), - ); + appBar: AppBar( + title: Text(widget.title), + actions: [ + IconButton( + onPressed: () { + var route = MaterialPageRoute( + builder: (context) => const SearchScreen()); + Navigator.of(context).push(route); + }, + icon: const Icon(Icons.search)) + ], + ), + body: _screen(), + drawer: widget.showDrawer ? const DrawerScreen() : null, + floatingActionButton: + user == null ? null : _fabNewUpload() //_fab(user), + ); } } diff --git a/lib/src/screens/login/new_login_screen.dart b/lib/src/screens/login/new_login_screen.dart new file mode 100644 index 00000000..cedfd479 --- /dev/null +++ b/lib/src/screens/login/new_login_screen.dart @@ -0,0 +1,38 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:acela/src/screens/login/webview/navigation_controls.dart'; +import 'package:acela/src/screens/login/webview/webview_stack.dart'; +import 'package:flutter/material.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +class NewLoginScreen extends StatefulWidget { + const NewLoginScreen({Key? key}) : super(key: key); + + @override + State createState() => _NewLoginScreenState(); +} + +class _NewLoginScreenState extends State { + final controller = Completer(); + @override + void initState() { + if (Platform.isAndroid) { + WebView.platform = SurfaceAndroidWebView(); + } + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Login using HAS'), + actions: [ + NavigationControls(controller: controller), + ], + ), + body: WebViewStack(controller: controller), + ); + } +} diff --git a/lib/src/screens/login/webview/navigation_controls.dart b/lib/src/screens/login/webview/navigation_controls.dart new file mode 100644 index 00000000..42169d01 --- /dev/null +++ b/lib/src/screens/login/webview/navigation_controls.dart @@ -0,0 +1,67 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +class NavigationControls extends StatelessWidget { + const NavigationControls({required this.controller, Key? key}); + + final Completer controller; + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: controller.future, + builder: (context, snapshot) { + final WebViewController? controller = snapshot.data; + if (snapshot.connectionState != ConnectionState.done || + controller == null) { + return Row( + children: const [ + // Icon(Icons.arrow_back_ios), + // Icon(Icons.arrow_forward_ios), + Icon(Icons.replay), + ], + ); + } + + return Row( + children: [ + // IconButton( + // icon: const Icon(Icons.arrow_back_ios), + // onPressed: () async { + // if (await controller.canGoBack()) { + // await controller.goBack(); + // } else { + // ScaffoldMessenger.of(context).showSnackBar( + // const SnackBar(content: Text('No back history item')), + // ); + // return; + // } + // }, + // ), + // IconButton( + // icon: const Icon(Icons.arrow_forward_ios), + // onPressed: () async { + // if (await controller.canGoForward()) { + // await controller.goForward(); + // } else { + // ScaffoldMessenger.of(context).showSnackBar( + // const SnackBar(content: Text('No forward history item')), + // ); + // return; + // } + // }, + // ), + IconButton( + icon: const Icon(Icons.replay), + onPressed: () { + controller.reload(); + }, + ), + ], + ); + }, + ); + } +} diff --git a/lib/src/screens/login/webview/webview_stack.dart b/lib/src/screens/login/webview/webview_stack.dart new file mode 100644 index 00000000..04c3d8be --- /dev/null +++ b/lib/src/screens/login/webview/webview_stack.dart @@ -0,0 +1,52 @@ +import 'dart:async'; // Add this import for Completer + +import 'package:flutter/material.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +class WebViewStack extends StatefulWidget { + const WebViewStack({required this.controller, Key? key}); // Modify + + final Completer controller; // Add this attribute + + @override + State createState() => _WebViewStackState(); +} + +class _WebViewStackState extends State { + var loadingPercentage = 0; + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + WebView( + initialUrl: 'https://sag333ar.github.io/webviewexp.github.io/', + // Add from here ... + onWebViewCreated: (webViewController) { + widget.controller.complete(webViewController); + }, + // ... to here. + onPageStarted: (url) { + setState(() { + loadingPercentage = 0; + }); + }, + onProgress: (progress) { + setState(() { + loadingPercentage = progress; + }); + }, + onPageFinished: (url) { + setState(() { + loadingPercentage = 100; + }); + }, + ), + if (loadingPercentage < 100) + LinearProgressIndicator( + value: loadingPercentage / 100.0, + ), + ], + ); + } +} diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index d9dfe45b..f283ad5c 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -157,7 +157,7 @@ class _MyAccountScreenState extends State { future: loadVideos, builder: (context, snapshot) { if (snapshot.hasError) { - return Center(child: const Text('Something went wrong')); + return const Center(child: Text('Something went wrong')); } else if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) { return _videosList(snapshot.data as List, user); @@ -184,7 +184,7 @@ class _MyAccountScreenState extends State { appBar: _appBar(username), body: Container( child: user == null - ? Center(child: const Text('Nothing')) + ? const Center(child: Text('Nothing')) : isLoading ? Center( child: LoadingScreen( diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart new file mode 100644 index 00000000..3f276364 --- /dev/null +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -0,0 +1,188 @@ +import 'dart:async'; +import 'dart:developer'; +import 'dart:io'; + +import 'package:acela/src/utils/communicator.dart'; +import 'package:cross_file/cross_file.dart' show XFile; +import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; +import 'package:ffmpeg_kit_flutter/media_information_session.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:tus_client/tus_client.dart'; +import 'package:video_compress/video_compress.dart'; +import 'package:video_thumbnail/video_thumbnail.dart'; + +class NewVideoUploadScreen extends StatefulWidget { + const NewVideoUploadScreen({Key? key}) : super(key: key); + + @override + State createState() => _NewVideoUploadScreenState(); +} + +class _NewVideoUploadScreenState extends State { + var didShowFilePicker = false; + var didPickFile = false; + var didCompress = false; + var didUpload = false; + var progress = 0.0; + var compressionProgress = 0.0; + late Subscription _subscription; + + @override + void initState() { + super.initState(); + _subscription = VideoCompress.compressProgress$.subscribe((progress) { + debugPrint('progress: $progress'); + setState(() { + compressionProgress = progress; + }); + }); + Timer.periodic(const Duration(seconds: 1), (timer) { + timer.cancel(); + videoPickerFunction(); + }); + } + + @override + void dispose() { + super.dispose(); + _subscription.unsubscribe(); + } + + void videoPickerFunction() async { + setState(() { + didShowFilePicker = true; + }); + try { + FilePickerResult? fileResult = + await FilePicker.platform.pickFiles(type: FileType.video); + if (fileResult != null && fileResult.files.single.path != null) { + setState(() { + didPickFile = true; + }); + PlatformFile file = fileResult.files.single; + log(file.name); + log("bytes - ${file.bytes ?? 0}"); + log("size - ${file.size}"); + log("Extension - ${file.extension}"); + log("path - ${file.path}"); + final compressInfo = await VideoCompress.compressVideo( + file.path!, + quality: VideoQuality.Res960x540Quality, + deleteOrigin: false, + includeAudio: true, + ); + setState(() { + didCompress = true; + }); + var fileSize = compressInfo?.filesize ?? file.size; + var sizeInMb = fileSize / 1000 / 1000; + if (sizeInMb > 500) { + throw 'Video is too big to be uploaded from mobile (exceeding 500 mb)'; + } + var path = compressInfo?.file?.path ?? file.path!; + MediaInformationSession session = + await FFprobeKit.getMediaInformation(path); + var info = session.getMediaInformation(); + var duration = + (double.tryParse(info?.getDuration() ?? "0.0") ?? 0.0).toInt(); + log('Video duration is $duration'); + var name = await initiateUpload(path); + log('Uploaded file name is $name'); + throw 'compression, upload done'; + } else { + throw 'User cancelled the video picker'; + } + } catch (e) { + rethrow; + } + } + + Future initiateUpload(String path) async { + final xfile = XFile(path); + final client = TusClient( + Uri.parse(Communicator.fsServer), + xfile, + store: TusMemoryStore(), + ); + var name = ""; + await client.upload( + onComplete: () async { + log("Complete!"); + // Prints the uploaded file URL + log(client.uploadUrl.toString()); + var url = client.uploadUrl.toString(); + var ipfsName = url.replaceAll("${Communicator.fsServer}/", ""); + // var pathImageThumb = await getThumbnail(xfile.path); + setState(() { + // this.ipfsName = ipfsName; + // this.thumbUrl = pathImageThumb; + didUpload = true; + }); + name = ipfsName; + }, + onProgress: (progress) { + log("Progress: $progress"); + setState(() { + this.progress = progress / 100.0; + }); + }, + ); + return name; + } + + Future getThumbnail(String path) async { + Directory tempDir = Directory.systemTemp; + var imagePath = await VideoThumbnail.thumbnailFile( + video: path, + thumbnailPath: tempDir.path, + imageFormat: ImageFormat.PNG, + maxWidth: 320, + quality: 100, + ); + return imagePath; + } + + @override + Widget build(BuildContext context) { + // if (!didShowFilePicker) { + // videoPickerFunction(); + // } + return Scaffold( + appBar: AppBar( + title: const Text('Upload Video'), + ), + body: ListView( + children: [ + ListTile( + title: const Text('Selecting video'), + trailing: !didPickFile + ? const CircularProgressIndicator() + : const Icon(Icons.check), + ), + ListTile( + title: Text( + 'Compressing video (${compressionProgress.toStringAsFixed(2)}%)'), + trailing: !didCompress + ? SizedBox( + width: 200, + child: LinearProgressIndicator( + value: compressionProgress / 100.0), + ) + : const Icon(Icons.check), + ), + ListTile( + title: Text( + 'Uploading video (${(progress * 100).toStringAsFixed(2)}%)'), + trailing: !didUpload + ? SizedBox( + width: 200, + child: LinearProgressIndicator(value: progress), + ) + : const Icon(Icons.check), + ), + ], + ), + ); + } +} diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 12a7d361..da25619f 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -19,16 +19,16 @@ import 'package:http/http.dart' as http; class Communicator { // Production - static const tsServer = "https://studio.3speak.tv"; - static const fsServer = "https://uploads.3speak.tv/files"; + // static const tsServer = "https://studio.3speak.tv"; + // static const fsServer = "https://uploads.3speak.tv/files"; // Android // static const fsServer = "http://10.0.2.2:1080/files"; // static const tsServer = "http://10.0.2.2:13050"; // iOS - // static const tsServer = "http://localhost:13050"; - // static const fsServer = "http://localhost:1080/files"; + static const tsServer = "http://localhost:13050"; + static const fsServer = "http://localhost:1080/files"; static const hiveApiUrl = 'https://api.hive.blog/'; diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 0f9ac75f..0b6eafb4 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,6 +11,7 @@ import flutter_secure_storage_macos import path_provider_macos import share_plus_macos import url_launcher_macos +import video_compress import wakelock_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { @@ -20,5 +21,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + VideoCompressPlugin.register(with: registry.registrar(forPlugin: "VideoCompressPlugin")) WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index e7f4dc86..f70033ba 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,7 +7,7 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "42.0.0" + version: "43.0.0" adaptive_action_sheet: dependency: "direct main" description: @@ -21,7 +21,7 @@ packages: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "4.3.0" + version: "4.3.1" args: dependency: transitive description: @@ -175,7 +175,7 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "4.2.0" collection: dependency: transitive description: @@ -610,14 +610,14 @@ packages: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.16" + version: "2.0.17" path_provider_ios: dependency: transitive description: name: path_provider_ios url: "https://pub.dartlang.org" source: hosted - version: "2.0.10" + version: "2.0.11" path_provider_linux: dependency: transitive description: @@ -757,7 +757,7 @@ packages: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.3.1" + version: "1.3.2" shelf_web_socket: dependency: transitive description: @@ -940,6 +940,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + video_compress: + dependency: "direct main" + description: + name: video_compress + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" video_player: dependency: "direct main" description: @@ -1045,6 +1052,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.0" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.4" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.9.2" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.9.1" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + url: "https://pub.dartlang.org" + source: hosted + version: "2.9.2" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b90fcab0..4fd95fe4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,7 +59,9 @@ dependencies: url_launcher: ^6.0.20 video_player: ^2.2.14 video_player_web_hls: ^0.1.11+3 + video_compress: ^3.1.0 video_thumbnail: ^0.5.0 + webview_flutter: ^3.0.4 dev_dependencies: flutter_test: From d13affa5c62a58b099dcd4218700e7225eeb46d4 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 5 Aug 2022 13:27:41 +0530 Subject: [PATCH 104/466] The new video upload. --- .flutter-plugins-dependencies | 2 +- .../video_upload_complete_request.dart | 29 +++ .../manage_notifications.dart | 189 --------------- .../upload/new_video_upload_screen.dart | 218 ++++++++++++++---- lib/src/utils/communicator.dart | 136 +++-------- 5 files changed, 246 insertions(+), 328 deletions(-) delete mode 100644 lib/src/screens/my_account/account_settings/manage_notifications.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 00ba147f..84adb2e3 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-05 03:07:49.835916","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-05 13:25:32.306471","version":"3.0.4"} \ No newline at end of file diff --git a/lib/src/models/video_upload/video_upload_complete_request.dart b/lib/src/models/video_upload/video_upload_complete_request.dart index 0c257bd1..5e25e640 100644 --- a/lib/src/models/video_upload/video_upload_complete_request.dart +++ b/lib/src/models/video_upload/video_upload_complete_request.dart @@ -31,3 +31,32 @@ class VideoUploadCompleteRequest { String toJsonString() => json.encode(toJson()); } + +class NewVideoUploadCompleteRequest { + final String oFilename; + final int duration; + final double size; + final String filename; + final String thumbnail; + final String owner; + + NewVideoUploadCompleteRequest({ + required this.oFilename, + required this.duration, + required this.size, + required this.filename, + required this.thumbnail, + required this.owner, + }); + + Map toJson() => { + 'filename': filename, + 'oFilename': oFilename, + 'size': size, + 'duration': duration, + 'thumbnail': thumbnail, + 'owner': owner, + }; + + String toJsonString() => json.encode(toJson()); +} diff --git a/lib/src/screens/my_account/account_settings/manage_notifications.dart b/lib/src/screens/my_account/account_settings/manage_notifications.dart deleted file mode 100644 index 79eb9c9b..00000000 --- a/lib/src/screens/my_account/account_settings/manage_notifications.dart +++ /dev/null @@ -1,189 +0,0 @@ -import 'package:acela/src/models/my_account/my_devices.dart'; -import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/utils/communicator.dart'; -import 'package:acela/src/widgets/loading_screen.dart'; -// import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -class ManageNotificationsScreen extends StatefulWidget { - const ManageNotificationsScreen({Key? key}) : super(key: key); - - @override - State createState() => - _ManageNotificationsScreenState(); -} - -class _ManageNotificationsScreenState extends State { - Future>? getDevices; - var isDeletingOrSending = false; - - void showError(String string) { - var snackBar = SnackBar(content: Text('Error: $string')); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - - void deleteToken(String token, HiveUserData user) async { - setState(() { - isDeletingOrSending = true; - }); - try { - await Communicator().deleteToken(user, token); - } catch (e) { - showError("Something went wrong\n${e.toString()}"); - } finally { - setState(() { - isDeletingOrSending = false; - getDevices = null; - }); - } - } - - Widget _deviceList(List list, HiveUserData user) { - if (list.isEmpty) { - return Center( - child: ConstrainedBox( - constraints: BoxConstraints(maxWidth: 220), - child: Text( - "No devices are added for notifications.\n\nTap on Plus, to get notified when your video finishes the processing and ready for publishing.", - textAlign: TextAlign.center, - ), - ), - ); - } - return Container( - margin: EdgeInsets.only(top: 10), - child: ListView.separated( - itemBuilder: (c, i) { - var tokenSuffix = list[i].token.substring(list[i].token.length - 10); - return ListTile( - leading: const Icon(Icons.phone_android), - subtitle: Text("Push Token ending with $tokenSuffix"), - trailing: IconButton( - onPressed: () { - deleteToken(list[i].token, user); - }, - icon: const Icon(Icons.delete), - ), - title: Text(list[i].deviceName), - ); - }, - separatorBuilder: (c, i) => Divider(), - itemCount: list.length, - ), - ); - } - - Widget _futureForDevices(HiveUserData user) { - return FutureBuilder( - future: getDevices, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Center(child: const Text('Something went wrong')); - } else if (snapshot.hasData && - snapshot.connectionState == ConnectionState.done) { - return _deviceList(snapshot.data as List, user); - } else { - return const LoadingScreen( - title: 'Loading Data', - subtitle: 'Please wait', - ); - } - }, - ); - } - - // void registerForNotification(HiveUserData user) async { - // setState(() { - // isDeletingOrSending = true; - // }); - // try { - // final fcmToken = await FirebaseMessaging.instance.getToken(); - // var model = ''; - // DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); - // if (Platform.isAndroid) { - // AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; - // print('Running on ${androidInfo.model}'); - // model = androidInfo.model ?? 'Some Android Device'; - // } else if (Platform.isIOS) { - // IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo; - // print('Running on ${iosDeviceInfo.model}'); - // model = iosDeviceInfo.model ?? 'Some iOS Device'; - // } else { - // model = 'Unknown Device type'; - // } - // log('FCM Token is $fcmToken'); - // await Communicator().addToken(user, fcmToken ?? "", model); - // } catch (e) { - // showError("Something went wrong\n${e.toString()}"); - // } finally { - // setState(() { - // isDeletingOrSending = false; - // getDevices = null; - // }); - // } - // } - - void sendTestNotification(HiveUserData user) async { - // testTokens - setState(() { - isDeletingOrSending = true; - }); - try { - await Communicator().testTokens(user); - } catch (e) { - showError("Something went wrong\n${e.toString()}"); - } finally { - setState(() { - isDeletingOrSending = false; - }); - } - } - - @override - Widget build(BuildContext context) { - var user = Provider.of(context); - if (user == null) { - return Scaffold( - appBar: AppBar( - title: const Text('Manage Notifications'), - ), - body: SafeArea( - child: const Text('Please re-login'), - ), - ); - } - if (getDevices == null) { - setState(() { - getDevices = Communicator().loadDevices(user); - }); - } - return Scaffold( - appBar: AppBar( - title: const Text('Manage Notifications'), - actions: isDeletingOrSending - ? [] - : [ - IconButton( - onPressed: () { - sendTestNotification(user); - }, - icon: Icon(Icons.notifications)) - ], - ), - body: SafeArea( - child: isDeletingOrSending - ? const Center(child: CircularProgressIndicator()) - : _futureForDevices(user), - ), - // floatingActionButton: isDeletingOrSending - // ? null - // : FloatingActionButton( - // onPressed: () { - // registerForNotification(user); - // }, - // child: const Icon(Icons.add), - // ), - ); - } -} diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index 3f276364..dc6afa27 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -2,12 +2,14 @@ import 'dart:async'; import 'dart:developer'; import 'dart:io'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:cross_file/cross_file.dart' show XFile; import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; import 'package:ffmpeg_kit_flutter/media_information_session.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:tus_client/tus_client.dart'; import 'package:video_compress/video_compress.dart'; import 'package:video_thumbnail/video_thumbnail.dart'; @@ -24,9 +26,22 @@ class _NewVideoUploadScreenState extends State { var didPickFile = false; var didCompress = false; var didUpload = false; + var didTakeDefaultThumbnail = false; + var didUploadThumbnail = false; + var didMoveToQueue = false; + + var didStartPickFile = false; + var didStartCompress = false; + var didStartUpload = false; + var didStartTakeDefaultThumbnail = false; + var didStartUploadThumbnail = false; + var didStartMoveToQueue = false; + var progress = 0.0; + var thumbnailUploadProgress = 0.0; var compressionProgress = 0.0; late Subscription _subscription; + HiveUserData? user; @override void initState() { @@ -50,10 +65,15 @@ class _NewVideoUploadScreenState extends State { } void videoPickerFunction() async { - setState(() { - didShowFilePicker = true; - }); try { + if (user == null) { + throw 'User not logged in'; + } + // Step 1. Select Video + setState(() { + didStartPickFile = true; + didShowFilePicker = true; + }); FilePickerResult? fileResult = await FilePicker.platform.pickFiles(type: FileType.video); if (fileResult != null && fileResult.files.single.path != null) { @@ -61,20 +81,33 @@ class _NewVideoUploadScreenState extends State { didPickFile = true; }); PlatformFile file = fileResult.files.single; + var originalFileName = file.name; log(file.name); log("bytes - ${file.bytes ?? 0}"); log("size - ${file.size}"); log("Extension - ${file.extension}"); log("path - ${file.path}"); + // ---- Step 1. Select Video + + // Step 2. Compress Video + setState(() { + didStartCompress = true; + }); final compressInfo = await VideoCompress.compressVideo( file.path!, - quality: VideoQuality.Res960x540Quality, + quality: VideoQuality.Res640x480Quality, deleteOrigin: false, includeAudio: true, ); setState(() { didCompress = true; }); + // --- Step 2. Compress Video + + // Step 3. Video upload + setState(() { + didStartUpload = true; + }); var fileSize = compressInfo?.filesize ?? file.size; var sizeInMb = fileSize / 1000 / 1000; if (sizeInMb > 500) { @@ -87,18 +120,73 @@ class _NewVideoUploadScreenState extends State { var duration = (double.tryParse(info?.getDuration() ?? "0.0") ?? 0.0).toInt(); log('Video duration is $duration'); - var name = await initiateUpload(path); + var name = await initiateUpload(path, false); + setState(() { + didUpload = true; + }); + // --- Step 3. Video upload + + // Step 4. Generate Thumbnail + setState(() { + didStartTakeDefaultThumbnail = true; + }); + var thumbPath = await getThumbnail(path); + setState(() { + didTakeDefaultThumbnail = true; + }); + // --- Step 4. Generate Thumbnail + + // Step 5. Upload Thumbnail + setState(() { + didStartUploadThumbnail = true; + }); + var thumbName = await initiateUpload(thumbPath, true); + setState(() { + didUploadThumbnail = true; + }); + // --- Step 5. Upload Thumbnail log('Uploaded file name is $name'); + log('Uploaded thumbnail file name is $thumbName'); + + // Step 6. Move Video to Queue + setState(() { + didStartMoveToQueue = true; + }); + var videoUploadInfo = await Communicator().newUploadComplete( + user: user!, + thumbnail: thumbName, + oFilename: originalFileName, + duration: duration, + size: fileSize.toDouble(), + tusFileName: name, + ); + log(videoUploadInfo.status); + setState(() { + didMoveToQueue = true; + showMessage('Video is uploaded & moved to encoding queue'); + }); + // Step 6. Move Video to Queue + throw 'compression, upload done'; } else { throw 'User cancelled the video picker'; } } catch (e) { + if (e.toString() == "User cancelled the video picker") { + setState(() { + Navigator.of(context).pop(); + }); + } rethrow; } } - Future initiateUpload(String path) async { + void showMessage(String string) { + var snackBar = SnackBar(content: Text('Message: $string')); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + Future initiateUpload(String path, bool isThumbnail) async { final xfile = XFile(path); final client = TusClient( Uri.parse(Communicator.fsServer), @@ -117,69 +205,121 @@ class _NewVideoUploadScreenState extends State { setState(() { // this.ipfsName = ipfsName; // this.thumbUrl = pathImageThumb; - didUpload = true; + if (isThumbnail) { + didUploadThumbnail = true; + } else { + didUpload = true; + } }); name = ipfsName; }, onProgress: (progress) { log("Progress: $progress"); setState(() { - this.progress = progress / 100.0; + if (isThumbnail) { + thumbnailUploadProgress = progress / 100.0; + } else { + this.progress = progress / 100.0; + } }); }, ); return name; } - Future getThumbnail(String path) async { - Directory tempDir = Directory.systemTemp; - var imagePath = await VideoThumbnail.thumbnailFile( - video: path, - thumbnailPath: tempDir.path, - imageFormat: ImageFormat.PNG, - maxWidth: 320, - quality: 100, - ); - return imagePath; + Future getThumbnail(String path) async { + try { + Directory tempDir = Directory.systemTemp; + var imagePath = await VideoThumbnail.thumbnailFile( + video: path, + thumbnailPath: tempDir.path, + imageFormat: ImageFormat.PNG, + maxWidth: 320, + quality: 100, + ); + if (imagePath == null) { + throw 'Could not generate video thumbnail'; + } + return imagePath; + } catch (e) { + throw 'Error generating video thumbnail ${e.toString()}'; + } } @override Widget build(BuildContext context) { - // if (!didShowFilePicker) { - // videoPickerFunction(); - // } + var user = Provider.of(context); + if (user != null && this.user == null) { + this.user = user; + } return Scaffold( appBar: AppBar( - title: const Text('Upload Video'), + title: const Text('Video Upload Process'), ), body: ListView( children: [ ListTile( - title: const Text('Selecting video'), + title: const Text('Selecting & processing video'), trailing: !didPickFile - ? const CircularProgressIndicator() + ? !didStartPickFile + ? const Icon(Icons.pending) + : const CircularProgressIndicator() : const Icon(Icons.check), ), ListTile( title: Text( - 'Compressing video (${compressionProgress.toStringAsFixed(2)}%)'), - trailing: !didCompress - ? SizedBox( - width: 200, - child: LinearProgressIndicator( - value: compressionProgress / 100.0), - ) - : const Icon(Icons.check), + 'Compressing video (${didCompress ? 100.0 : compressionProgress.toStringAsFixed(2)}%)'), + trailing: !didStartCompress + ? const Icon(Icons.pending) + : !didCompress + ? SizedBox( + width: 200, + child: LinearProgressIndicator( + value: compressionProgress / 100.0), + ) + : const Icon(Icons.check), ), ListTile( title: Text( - 'Uploading video (${(progress * 100).toStringAsFixed(2)}%)'), - trailing: !didUpload - ? SizedBox( - width: 200, - child: LinearProgressIndicator(value: progress), - ) - : const Icon(Icons.check), + 'Uploading video (${didUpload ? 100.0 : (progress * 100).toStringAsFixed(2)}%)'), + trailing: !didStartUpload + ? const Icon(Icons.pending) + : !didUpload + ? SizedBox( + width: 200, + child: LinearProgressIndicator(value: progress), + ) + : const Icon(Icons.check), + ), + ListTile( + title: const Text('Taking video thumbnail'), + subtitle: const Text('You can edit thumbnail later'), + trailing: !didStartTakeDefaultThumbnail + ? const Icon(Icons.pending) + : !didTakeDefaultThumbnail + ? const CircularProgressIndicator() + : const Icon(Icons.check), + ), + ListTile( + title: Text( + 'Uploading thumbnail (${didUpload ? 100.0 : (thumbnailUploadProgress * 100).toStringAsFixed(2)}%)'), + trailing: !didStartUploadThumbnail + ? const Icon(Icons.pending) + : !didUploadThumbnail + ? SizedBox( + width: 200, + child: LinearProgressIndicator( + value: thumbnailUploadProgress), + ) + : const Icon(Icons.check), + ), + ListTile( + title: const Text('Move video to Encoding Queue'), + trailing: !didStartMoveToQueue + ? const Icon(Icons.pending) + : !didMoveToQueue + ? const CircularProgressIndicator() + : const Icon(Icons.check), ), ], ), diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index da25619f..fad10042 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -6,7 +6,6 @@ import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/hive_post_info/hive_user_posting_key.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/login/memo_response.dart'; -import 'package:acela/src/models/my_account/my_devices.dart'; import 'package:acela/src/models/my_account/video_ops.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; @@ -202,68 +201,47 @@ class Communicator { } } - Future addToken(HiveUserData user, String token, String model) async { - var request = http.Request( - 'POST', Uri.parse('${Communicator.tsServer}/mobile/api/token/add')); - request.body = "{\"token\": \"$token\", \"deviceName\": \"$model\"}"; - Map map = { - "cookie": user.cookie ?? "", - "Content-Type": "application/json" - }; - request.headers.addAll(map); - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - log("Successfully registered token"); - return; - } else { - var string = await response.stream.bytesToString(); - var error = ErrorResponse.fromJsonString(string).error ?? - response.reasonPhrase.toString(); - log('Error from server is $error'); - throw error; - } - } - - Future removeToken(HiveUserData user, String token) async { - var request = http.Request( - 'POST', Uri.parse('${Communicator.tsServer}/mobile/api/token/remove')); - request.body = "{\"token\": \"$token\"}"; - Map map = { - "cookie": user.cookie ?? "", - "Content-Type": "application/json" - }; - request.headers.addAll(map); - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - log("Successfully un-registered token"); - return; - } else { - var string = await response.stream.bytesToString(); - var error = ErrorResponse.fromJsonString(string).error ?? - response.reasonPhrase.toString(); - log('Error from server is $error'); - throw error; - } - } - - Future testTokens(HiveUserData user) async { - var request = http.Request( - 'GET', Uri.parse('${Communicator.tsServer}/mobile/api/token/test')); + Future newUploadComplete({ + required HiveUserData user, + required String thumbnail, + required String oFilename, + required int duration, + required double size, + required String tusFileName, + }) async { + var cookie = await getValidCookie(user); + var request = http.Request('POST', + Uri.parse('${Communicator.tsServer}/mobile/api/upload/newUpload')); + request.body = NewVideoUploadCompleteRequest( + size: size, + thumbnail: thumbnail, + oFilename: oFilename, + duration: duration, + filename: tusFileName, + owner: user.username, + ).toJsonString(); Map map = { - "cookie": user.cookie ?? "", + "cookie": cookie, "Content-Type": "application/json" }; request.headers.addAll(map); - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - log("Successfully un-registered token"); - return; - } else { - var string = await response.stream.bytesToString(); - var error = ErrorResponse.fromJsonString(string).error ?? - response.reasonPhrase.toString(); - log('Error from server is $error'); - throw error; + try { + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + log("Successfully sent upload complete"); + var string = await response.stream.bytesToString(); + log('Video complete response is\n$string'); + return VideoUploadInfo.fromJsonString(string); + } else { + var string = await response.stream.bytesToString(); + var error = ErrorResponse.fromJsonString(string).error ?? + response.reasonPhrase.toString(); + log('Error from server is $error'); + throw error; + } + } catch (e) { + log('Error from server is ${e.toString()}'); + rethrow; } } @@ -358,46 +336,6 @@ class Communicator { } } - Future> loadDevices(HiveUserData user) async { - var cookie = await getValidCookie(user); - var request = http.Request( - 'GET', Uri.parse('${Communicator.tsServer}/mobile/api/token/list')); - Map map = { - "cookie": cookie, - "Content-Type": "application/json" - }; - request.headers.addAll(map); - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - var string = await response.stream.bytesToString(); - return MyDevices.fromString(string).data; - } else { - var string = await response.stream.bytesToString(); - var error = ErrorResponse.fromJsonString(string).error ?? - response.reasonPhrase.toString(); - log('Error from server is $error'); - throw error; - } - } - - Future deleteToken(HiveUserData user, String token) async { - var cookie = await getValidCookie(user); - var request = http.Request( - 'POST', Uri.parse('${Communicator.tsServer}/mobile/api/token/remove')); - request.body = "{\"token\": \"$token\"}"; - Map map = { - "cookie": cookie, - "Content-Type": "application/json" - }; - request.headers.addAll(map); - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - return; - } else { - throw response.reasonPhrase.toString(); - } - } - Future updatePublishState(HiveUserData user, String videoId) async { var cookie = await getValidCookie(user); var request = http.Request('POST', From 929420a3d3f8c8614430208a8e07d84d73062add Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 8 Aug 2022 00:27:18 +0530 Subject: [PATCH 105/466] post to hive updated. --- .flutter-plugins-dependencies | 2 +- .idea/Android-App.iml | 6 + ios/Runner/public/index.html | 381 +++++++++++++----- .../screens/my_account/my_account_screen.dart | 160 ++++---- 4 files changed, 386 insertions(+), 163 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 84adb2e3..706b3a65 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-05 13:25:32.306471","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-07 22:30:59.632227","version":"3.0.4"} \ No newline at end of file diff --git a/.idea/Android-App.iml b/.idea/Android-App.iml index 64138120..e065b41a 100644 --- a/.idea/Android-App.iml +++ b/.idea/Android-App.iml @@ -92,6 +92,12 @@ + + + + + + diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index 68c032df..abd401d6 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -1,90 +1,283 @@ - - - - - - 3Speak Acela - - - - - - + - + diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index f283ad5c..5615e437 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -1,8 +1,4 @@ -import 'dart:convert'; -import 'dart:developer'; - import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/screens/my_account/account_settings/account_settings_screen.dart'; @@ -10,7 +6,6 @@ import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:provider/provider.dart'; @@ -24,8 +19,8 @@ class MyAccountScreen extends StatefulWidget { class _MyAccountScreenState extends State { Future>? loadVideos; Future? loadOperations; - var isLoading = false; - var loadingText = ''; + // var isLoading = false; + // var loadingText = ''; void logout() async { // Create storage @@ -36,47 +31,47 @@ class _MyAccountScreenState extends State { Navigator.of(context).pop(); } - void loadVideoInfo(HiveUserData user, String videoId) async { - setState(() { - isLoading = true; - loadingText = 'Getting video data to post on Hive'; - }); - try { - var result = await Communicator().loadOperations(user, videoId); - var utf8data = utf8.encode(result); - final base64Str = base64.encode(utf8data); - setState(() { - loadingText = 'Publishing on Hive'; - }); - var platform = MethodChannel('com.example.acela/auth'); - final String response = await platform.invokeMethod('postVideo', { - 'data': base64Str, - 'postingKey': user.postingKey, - }); - var bridgeResponse = LoginBridgeResponse.fromJsonString(response); - if (bridgeResponse.valid == true) { - setState(() { - loadingText = 'Marking video as published'; - }); - await Communicator().updatePublishState(user, videoId); - setState(() { - isLoading = false; - loadVideos = Communicator().loadVideos(user); - }); - } else { - showError('Error occurred: ${bridgeResponse.error}'); - } - log('Result from android platform is \n$response'); - setState(() { - isLoading = false; - }); - } catch (e) { - setState(() { - isLoading = false; - }); - showError('Error occurred - ${e.toString()}'); - } - } + // void loadVideoInfo(HiveUserData user, String videoId) async { + // setState(() { + // isLoading = true; + // loadingText = 'Getting video data to post on Hive'; + // }); + // try { + // var result = await Communicator().loadOperations(user, videoId); + // var utf8data = utf8.encode(result); + // final base64Str = base64.encode(utf8data); + // setState(() { + // loadingText = 'Publishing on Hive'; + // }); + // var platform = MethodChannel('com.example.acela/auth'); + // final String response = await platform.invokeMethod('postVideo', { + // 'data': base64Str, + // 'postingKey': user.postingKey, + // }); + // var bridgeResponse = LoginBridgeResponse.fromJsonString(response); + // if (bridgeResponse.valid == true) { + // setState(() { + // loadingText = 'Marking video as published'; + // }); + // await Communicator().updatePublishState(user, videoId); + // setState(() { + // isLoading = false; + // loadVideos = Communicator().loadVideos(user); + // }); + // } else { + // showError('Error occurred: ${bridgeResponse.error}'); + // } + // log('Result from android platform is \n$response'); + // setState(() { + // isLoading = false; + // }); + // } catch (e) { + // setState(() { + // isLoading = false; + // }); + // showError('Error occurred - ${e.toString()}'); + // } + // } void showError(String string) { var snackBar = SnackBar(content: Text('Error: $string')); @@ -96,14 +91,21 @@ class _MyAccountScreenState extends State { Text(username), ], ), + bottom: const TabBar( + tabs: [ + Tab(icon: Icon(Icons.hourglass_top)), + Tab(icon: Icon(Icons.rocket_launch)), + Tab(icon: Icon(Icons.check)), + ], + ), actions: [ IconButton( onPressed: () { - var screen = AccountSettingsScreen(); + var screen = const AccountSettingsScreen(); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); }, - icon: Icon(Icons.settings), + icon: const Icon(Icons.settings), ) ], ); @@ -111,18 +113,18 @@ class _MyAccountScreenState extends State { Widget _trailingActionOnVideoListItem(VideoDetails item, HiveUserData user) { return item.status == 'published' - ? Icon(Icons.check, color: Colors.green) + ? const Icon(Icons.check, color: Colors.green) : item.status == 'publish_manual' ? IconButton( onPressed: () { - loadVideoInfo(user, item.id); + // loadVideoInfo(user, item.id); }, - icon: Icon( + icon: const Icon( Icons.rocket_launch, color: Colors.green, ), ) - : Icon( + : const Icon( Icons.hourglass_top, color: Colors.blue, ); @@ -142,7 +144,12 @@ class _MyAccountScreenState extends State { ); } - Widget _videosList(List items, HiveUserData user) { + Widget _listViewForItems(List items, HiveUserData user) { + if (items.isEmpty) { + return const Center( + child: Text('No Items found.'), + ); + } return ListView.separated( itemBuilder: (context, index) { return _videoListItem(items[index], user); @@ -152,6 +159,28 @@ class _MyAccountScreenState extends State { ); } + Widget _videosList(List items, HiveUserData user) { + var published = items.where((item) => item.status == 'published').toList(); + var ready = items.where((item) => item.status == 'publish_manual').toList(); + var process = items + .where((item) => + item.status != 'published' && item.status != 'publish_manual') + .toList(); + return TabBarView( + children: [ + SafeArea( + child: _listViewForItems(process, user), + ), + SafeArea( + child: _listViewForItems(ready, user), + ), + SafeArea( + child: _listViewForItems(published, user), + ), + ], + ); + } + Widget _videoFuture(HiveUserData user) { return FutureBuilder( future: loadVideos, @@ -180,19 +209,14 @@ class _MyAccountScreenState extends State { }); } var username = user?.username ?? 'Unknown'; - return Scaffold( - appBar: _appBar(username), - body: Container( - child: user == null - ? const Center(child: Text('Nothing')) - : isLoading - ? Center( - child: LoadingScreen( - title: 'Publishing Your Video', - subtitle: loadingText, - ), - ) - : _videoFuture(user), + return DefaultTabController( + length: 3, + child: Scaffold( + appBar: _appBar(username), + body: Container( + child: user == null + ? const Center(child: Text('Nothing')) + : _videoFuture(user)), ), ); } From 7e7352264f2b30f57ac643a2dcb3338760c96dc9 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 8 Aug 2022 00:57:00 +0530 Subject: [PATCH 106/466] front-end changes. --- ios/Runner/public/index.html | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index abd401d6..a29be46b 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -181,7 +181,34 @@ }]; } + async function hivePostExist(author, permlink) { + try { + let content = await hive.api.getContentAsync(author, permlink); + + //Apparently Hive API returns a string when post is empty and object when post exists! :shrug: + if (typeof content === "string") { + return JSON.parse(content).result.length !== 0; + } else { + //Just to be sure there is actual content + return !!content.body; + } + } catch (e) { + console.log(e); + return false; + } + } + function newPostVideo(thumbnail,videoV2,dDescription,dTitle,tags,author,permlink,duration,size,file,language,firstUpload,thumbnail,cdn,postingKey,benes,beneWeights) { + let result = await hivePostExist(author,permlink); + if (result) { + var newResult = { + type: "postVideo", + valid: true, + error: "success", + }; + window.webkit.messageHandlers.acela.postMessage(result); + return; + } let description = atob(dDescription); description = decodeURIComponent(escape(description)); let title = atob(dTitle); From f9473bea748f654de1f4cee9c97f2aae32f21815 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 8 Aug 2022 01:07:39 +0530 Subject: [PATCH 107/466] front-end changes. --- ios/Runner/public/index.html | 61 ------------------------------------ 1 file changed, 61 deletions(-) diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index a29be46b..24e53271 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -243,11 +243,6 @@ } } } - newBen = newBen.filter((bene, index) => { - const _bene = bene.account; - return (index === newBen.findIndex((obj) => { - return (obj.account === _bene || ["wehmoen", "louis88", "detlev"].includes(obj.account)); - })); benes.split(",").forEach((string, index) => { const value = parseInt(beneWeights.split(",")[index]); newBen.push({ account: string, weight: value }); @@ -306,62 +301,6 @@ // Android.postMessage(JSON.stringify(result)); }); } - - function postVideo(data, postingKey) { - console.log(`Response received from server: ${data}`); - const bdata = atob(data); - const result = JSON.parse(bdata).data; - const json_metadata = JSON.stringify(result.json_metadata); - const video = result.videoBody; - let comment = { ...result.comment, json_metadata: json_metadata }; - comment.body = renderTemplate(video); - const newExtensions = result.extensions.sort((a, b) => { - let fa = a.account.toLowerCase(), - fb = b.account.toLowerCase(); - if (fa < fb) return -1; - if (fa > fb) return 1; - return 0; - }); - const comment_options = { - ...result.comment_options, - extensions: [[0, { beneficiaries: newExtensions }]], - }; - const json = JSON.stringify(result.custom_json.json); - const custom_json = { ...result.custom_json, json: json }; - const ops = [ - ["comment", comment], - ["comment_options", comment_options], - ["custom_json", custom_json], - ]; - console.log(`ops is ${ops}`); - async function tryPublish(operations, key) { - try { - return hive.broadcast.sendAsync({ operations }, { posting: key }); - } catch (e) { - return e; - } - } - tryPublish(ops, postingKey) - .then((result) => { - var newResult = { - type: "postVideo", - valid: true, - error: "success", - }; - window.webkit.messageHandlers.acela.postMessage(result); - // Android.postMessage(JSON.stringify(newResult)); - }) - .catch((error) => { - console.error(error); - var result = { - type: "postVideo", - valid: false, - error: error.message, - }; - window.webkit.messageHandlers.acela.postMessage(result); - // Android.postMessage(JSON.stringify(result)); - }); - } From 9a8ce52958f66cd3b4a364f949cc1c5b4d675703 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 8 Aug 2022 01:53:01 +0530 Subject: [PATCH 108/466] New video upload process --- ios/Runner/public/index.html | 2 +- .../screens/my_account/my_account_screen.dart | 5 +- .../update_video/video_details_info.dart | 252 ++++++++++++++++++ .../update_video/video_primary_info.dart | 83 ++++++ 4 files changed, 340 insertions(+), 2 deletions(-) create mode 100644 lib/src/screens/my_account/update_video/video_details_info.dart create mode 100644 lib/src/screens/my_account/update_video/video_primary_info.dart diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index 24e53271..e49e0c3b 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -198,7 +198,7 @@ } } - function newPostVideo(thumbnail,videoV2,dDescription,dTitle,tags,author,permlink,duration,size,file,language,firstUpload,thumbnail,cdn,postingKey,benes,beneWeights) { + function newPostVideo(thumbnail,videoV2,dDescription,dTitle,tags,author,permlink,duration,size,file,language,firstUpload,thumbnail,cdn,benes,beneWeights,postingKey) { let result = await hivePostExist(author,permlink); if (result) { var newResult = { diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 5615e437..e9509fe9 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -2,6 +2,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/screens/my_account/account_settings/account_settings_screen.dart'; +import 'package:acela/src/screens/my_account/update_video/video_primary_info.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; @@ -117,7 +118,9 @@ class _MyAccountScreenState extends State { : item.status == 'publish_manual' ? IconButton( onPressed: () { - // loadVideoInfo(user, item.id); + var screen = VideoPrimaryInfo(item: item); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); }, icon: const Icon( Icons.rocket_launch, diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart new file mode 100644 index 00000000..b233ee89 --- /dev/null +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -0,0 +1,252 @@ +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/models/video_details_model/video_details.dart'; +import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:cross_file/cross_file.dart' show XFile; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:tus_client/tus_client.dart'; + +class VideoDetailsInfo extends StatefulWidget { + const VideoDetailsInfo({ + Key? key, + required this.item, + required this.title, + required this.subtitle, + }) : super(key: key); + final VideoDetails item; + final String title; + final String subtitle; + + @override + State createState() => _VideoDetailsInfoState(); +} + +class _VideoDetailsInfoState extends State { + var isCompleting = false; + var isPickingImage = false; + var uploadStarted = false; + var uploadComplete = false; + var isNsfwContent = false; + var thumbIpfs = ''; + var thumbUrl = ''; + var tags = ''; + var progress = 0.0; + var processText = ''; + + void showError(String string) { + var snackBar = SnackBar(content: Text('Error: $string')); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + void showMessage(String string) { + var snackBar = SnackBar(content: Text('Message: $string')); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + void initiateUpload( + HiveUserData? data, + XFile xFile, + ) async { + if (uploadStarted) return; + setState(() { + uploadStarted = true; + }); + final client = TusClient( + Uri.parse(Communicator.fsServer), + xFile, + store: TusMemoryStore(), + ); + await client.upload( + onComplete: () async { + print("Complete!"); + print(client.uploadUrl.toString()); + var url = client.uploadUrl.toString(); + var ipfsName = url.replaceAll("${Communicator.fsServer}/", ""); + setState(() { + thumbUrl = url; + thumbIpfs = ipfsName; + uploadComplete = true; + uploadStarted = false; + }); + }, + onProgress: (progress) { + print("Progress: $progress"); + setState(() { + this.progress = progress; + }); + }, + ); + } + + void completeVideo(HiveUserData user) async { + setState(() { + isCompleting = true; + processText = 'Updating video info'; + }); + try { + // TO-DO change following to new video complete api + var videoUploadInfo = await Communicator().uploadComplete( + user: user, + videoId: widget.item.id, + name: widget.ipfsName, + title: widget.title, + description: widget.description, + isNsfwContent: isNsfwContent, + tags: tags, + thumbnail: thumbIpfs, + ); + print(videoUploadInfo.status); + showMessage('Video is uploaded & moved to encoding queue'); + setState(() { + isCompleting = false; + processText = ''; + }); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + } catch (e) { + showError(e.toString()); + } + } + + Widget _thumbnailPicker(HiveUserData? user) { + return Center( + child: Container( + width: 320, + height: 160, + margin: const EdgeInsets.all(10), + decoration: const BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(24.0), + topRight: Radius.circular(24.0), + ), + boxShadow: [ + BoxShadow( + color: Colors.black12, + spreadRadius: 3, + blurRadius: 3, + ) + ]), + child: InkWell( + child: Center( + child: isPickingImage + ? const CircularProgressIndicator() + : progress > 0.0 && progress < 100.0 + ? CircularProgressIndicator(value: progress) + : thumbUrl.isNotEmpty + ? Image.network( + thumbUrl, + width: 320, + height: 160, + ) + : const Text( + 'Tap here to add thumbnail for your video\n\nThumbnail is MANDATORY to set.', + textAlign: TextAlign.center), + ), + onTap: () async { + try { + setState(() { + isPickingImage = true; + }); + FilePickerResult? fileResult = + await FilePicker.platform.pickFiles(type: FileType.image); + if (fileResult != null && fileResult.files.single.path != null) { + setState(() { + isPickingImage = false; + }); + final xfile = XFile(fileResult.files.single.path!); + initiateUpload(user, xfile); + } else { + throw 'User cancelled image picker'; + } + } catch (e) { + showError(e.toString()); + setState(() { + isPickingImage = false; + }); + } + }, + ), + ), + ); + } + + Widget _tagField() { + return Container( + margin: const EdgeInsets.all(10), + child: TextField( + decoration: const InputDecoration( + hintText: 'Comma separated tags', + labelText: 'Tags', + ), + onChanged: (text) { + setState(() { + tags = text; + }); + }, + maxLines: 1, + minLines: 1, + maxLength: 150, + ), + ); + } + + Widget _notSafe() { + return Container( + margin: const EdgeInsets.all(10), + child: Row( + children: [ + const Text('Is this video NOT SAFE for work?'), + const Spacer(), + Switch( + value: isNsfwContent, + onChanged: (newVal) { + setState(() { + isNsfwContent = newVal; + }); + }, + ) + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + var user = Provider.of(context); + return Scaffold( + appBar: AppBar( + title: const Text('Provide more info'), + ), + body: isCompleting + ? Center( + child: LoadingScreen( + title: 'Please wait', + subtitle: processText, + ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _tagField(), + _notSafe(), + _thumbnailPicker(user), + const Text('Tap to change video thumbnail'), + ], + ), + floatingActionButton: isCompleting + ? null + : thumbIpfs.isNotEmpty + ? FloatingActionButton( + onPressed: () { + if (user != null) { + completeVideo(user); + } + }, + child: const Icon(Icons.save), + ) + : null, + ); + } +} diff --git a/lib/src/screens/my_account/update_video/video_primary_info.dart b/lib/src/screens/my_account/update_video/video_primary_info.dart new file mode 100644 index 00000000..cc127138 --- /dev/null +++ b/lib/src/screens/my_account/update_video/video_primary_info.dart @@ -0,0 +1,83 @@ +import 'package:acela/src/models/video_details_model/video_details.dart'; +import 'package:flutter/material.dart'; + +class VideoPrimaryInfo extends StatefulWidget { + const VideoPrimaryInfo({ + Key? key, + required this.item, + }) : super(key: key); + final VideoDetails item; + + @override + State createState() => _VideoPrimaryInfoState(); +} + +class _VideoPrimaryInfoState extends State { + var title = ''; + var description = ''; + + Widget _body() { + return SafeArea( + child: Container( + margin: const EdgeInsets.all(20), + child: Column( + children: [ + TextField( + decoration: const InputDecoration( + hintText: 'Video title goes here', + labelText: 'Title', + ), + onChanged: (text) { + setState(() { + title = text; + }); + }, + maxLines: 1, + minLines: 1, + maxLength: 150, + ), + TextFormField( + decoration: const InputDecoration( + hintText: 'Video description', + labelText: 'Description', + ), + onChanged: (text) { + setState(() { + description = text; + }); + }, + maxLines: 8, + minLines: 5, + ) + ], + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Video Info'), + ), + body: _body(), + floatingActionButton: title.isNotEmpty && description.isNotEmpty + ? FloatingActionButton( + onPressed: () { + // var screen = UploadExtraScreen( + // videoId: widget.videoId, + // title: title, + // description: description, + // ipfsName: ipfsName, + // thumbUrl: thumbUrl, + // ); + // var route = MaterialPageRoute(builder: (c) => screen); + // Navigator.of(context).push(route); + }, + child: const Text('Next'), + ) + : null, + ); + } +} From 8d9f9ca13a457ea11765cac43dc30278018f7dd3 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 9 Aug 2022 01:44:05 +0530 Subject: [PATCH 109/466] new video upload complete --- .flutter-plugins-dependencies | 2 +- ios/Runner/public/index.html | 18 +- .../video_details_model/video_details.dart | 32 ++- .../video_upload_complete_request.dart | 5 +- .../video_upload_prepare_response.dart | 34 +-- lib/src/screens/home_screen/home_screen.dart | 86 ------ .../update_video/video_details_info.dart | 40 ++- .../update_video/video_primary_info.dart | 17 +- .../upload/new_video_upload_screen.dart | 2 +- .../screens/upload/upload_extra_screen.dart | 258 ------------------ lib/src/screens/upload/upload_screen.dart | 169 ------------ lib/src/utils/communicator.dart | 42 +-- 12 files changed, 80 insertions(+), 625 deletions(-) delete mode 100644 lib/src/screens/upload/upload_extra_screen.dart delete mode 100644 lib/src/screens/upload/upload_screen.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 706b3a65..b7a12a62 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-07 22:30:59.632227","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-09 00:44:34.204612","version":"3.0.4"} \ No newline at end of file diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index e49e0c3b..8441248c 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -99,9 +99,6 @@ } function buildJSONMetadata(thumbnail,videoV2,description,title,tags,author,permlink,duration,size,file,language,firstUpload,cdn) { - // 1. Set the imageUrl - let imageUrl = cdn + `/ipfs/${thumbnail.replace("ipfs://", "")}`; - // 2. set the sourceMap const sourceMap = []; if (videoV2 !== undefined) { @@ -117,7 +114,7 @@ tags: processTags(tags.split(",")), app: "3speak/0.3.0", type: "3speak/video", - image: [imageUrl], + image: [thumbnail], video: { info: { platform: "3speak", @@ -134,7 +131,7 @@ ...sourceMap, { type: "thumbnail", - url: imageUrl, + url: thumbnail, }, ], }, @@ -154,11 +151,10 @@ .replace(/@@@description@@@/g, description); } - function videoObjectForBody(description, thumbnail, cdn, owner, permlink) { - let imageUrl = cdn + `/ipfs/${thumbnail.replace("ipfs://", "")}`; + function videoObjectForBody(description, thumbnail, owner, permlink) { let escapedVideoDescription = customStringEscaping(description); return { - baseThumbUrl: imageUrl, + baseThumbUrl: thumbnail, owner: owner, permlink: permlink, description: escapedVideoDescription, @@ -198,7 +194,7 @@ } } - function newPostVideo(thumbnail,videoV2,dDescription,dTitle,tags,author,permlink,duration,size,file,language,firstUpload,thumbnail,cdn,benes,beneWeights,postingKey) { + function newPostVideo(thumbnail,videoV2,dDescription,dTitle,tags,author,permlink,duration,size,file,language,firstUpload,benes,beneWeights,postingKey) { let result = await hivePostExist(author,permlink); if (result) { var newResult = { @@ -213,7 +209,7 @@ description = decodeURIComponent(escape(description)); let title = atob(dTitle); title = decodeURIComponent(escape(title)); - let jsonMetaData = buildJSONMetadata(thumbnail,videoV2,description,title,tags,author,permlink,duration,size,file,language,firstUpload,cdn); + let jsonMetaData = buildJSONMetadata(thumbnail,videoV2,description,title,tags,author,permlink,duration,size,file,language,firstUpload); let customJson = buildPublishCustomJson(author,permlink,language,duration,title); let newBen = [ { account: "threespeakleader", weight: 100 }, @@ -255,7 +251,7 @@ allow_curation_rewards: true, extensions: benefactor_global }]; - let videoObject = videoObjectForBody(description, thumbnail, cdn, author, permlink); + let videoObject = videoObjectForBody(description, thumbnail, author, permlink); let body = renderTemplate(videoObject.baseThumbUrl,videoObject.owner,videoObject.permlink,videoObject.description); hive.broadcast.updateOperations(); const operations = []; diff --git a/lib/src/models/video_details_model/video_details.dart b/lib/src/models/video_details_model/video_details.dart index a9d031c5..b8c21040 100644 --- a/lib/src/models/video_details_model/video_details.dart +++ b/lib/src/models/video_details_model/video_details.dart @@ -15,20 +15,26 @@ class VideoDetails { final List tagsV2; final String id; final String community; - final String permlink; - final double duration; - final int size; final String owner; - final String description; - final String thumbnail; - final String title; - final String thumbUrl; final String baseThumbUrl; final bool steemPosted; final String status; - final String playUrl; + final String thumbnail; + + final String thumbUrl; + final String video_v2; + final String description; + final String title; + final String tags; + final String permlink; + final double duration; + final int size; + final String originalFilename; + final bool firstUpload; + final String beneficiaries; + VideoDetails({ this.created = "", this.paid = false, @@ -48,6 +54,11 @@ class VideoDetails { this.playUrl = "", this.steemPosted = false, this.status = "", + required this.video_v2, + required this.tags, + required this.originalFilename, + required this.firstUpload, + required this.beneficiaries, }); factory VideoDetails.fromJsonString(String jsonString) => @@ -72,6 +83,11 @@ class VideoDetails { playUrl: asString(json, 'playUrl'), steemPosted: asBool(json, 'steemPosted'), status: asString(json, 'status'), + tags: asString(json, 'tags'), + video_v2: asString(json, 'video_v2'), + originalFilename: asString(json, 'originalFilename'), + firstUpload: asBool(json, 'firstUpload'), + beneficiaries: asString(json, 'beneficiaries'), ); String toJsonString() => json.encode(toJson()); diff --git a/lib/src/models/video_upload/video_upload_complete_request.dart b/lib/src/models/video_upload/video_upload_complete_request.dart index 5e25e640..26e80423 100644 --- a/lib/src/models/video_upload/video_upload_complete_request.dart +++ b/lib/src/models/video_upload/video_upload_complete_request.dart @@ -2,16 +2,14 @@ import 'dart:convert'; class VideoUploadCompleteRequest { final String videoId; - final String filename; final String title; final String description; final bool isNsfwContent; final String tags; - final String thumbnail; + final String? thumbnail; VideoUploadCompleteRequest({ required this.videoId, - required this.filename, required this.title, required this.description, required this.isNsfwContent, @@ -21,7 +19,6 @@ class VideoUploadCompleteRequest { Map toJson() => { 'videoId': videoId, - 'filename': filename, 'title': title, 'description': description, 'isNsfwContent': isNsfwContent, diff --git a/lib/src/models/video_upload/video_upload_prepare_response.dart b/lib/src/models/video_upload/video_upload_prepare_response.dart index 2a00f99b..de4c5b38 100644 --- a/lib/src/models/video_upload/video_upload_prepare_response.dart +++ b/lib/src/models/video_upload/video_upload_prepare_response.dart @@ -47,7 +47,6 @@ class VideoUploadPrepareResponse { } class VideoUploadInfo { - final VideoEncoding encoding; final bool updateSteem; final bool lowRc; final bool needsBlockchainUpdate; @@ -82,9 +81,9 @@ class VideoUploadInfo { final String owner; final String uploadType; final int v; + final String cdn; VideoUploadInfo({ - required this.encoding, this.updateSteem = false, this.lowRc = false, this.needsBlockchainUpdate = false, @@ -119,6 +118,7 @@ class VideoUploadInfo { this.owner = "", this.uploadType = "", this.v = 0, + this.cdn = "https://ipfs-3speak.b-cdn.net", }); factory VideoUploadInfo.fromJsonString(String jsonString) => @@ -126,7 +126,6 @@ class VideoUploadInfo { factory VideoUploadInfo.fromJson(Map? json) => VideoUploadInfo( - encoding: VideoEncoding.fromJson(asMap(json, 'encoding')), updateSteem: asBool(json, 'updateSteem'), lowRc: asBool(json, 'lowRc'), needsBlockchainUpdate: asBool(json, 'needsBlockchainUpdate'), @@ -164,7 +163,6 @@ class VideoUploadInfo { ); Map toJson() => { - 'encoding': encoding.toJson(), 'updateSteem': updateSteem, 'lowRc': lowRc, 'needsBlockchainUpdate': needsBlockchainUpdate, @@ -201,31 +199,3 @@ class VideoUploadInfo { '__v': v, }; } - -class VideoEncoding { - final bool e360; - final bool e480; - final bool e720; - final bool e1080; - - VideoEncoding({ - this.e360 = false, - this.e480 = false, - this.e720 = false, - this.e1080 = false, - }); - - factory VideoEncoding.fromJson(Map? json) => VideoEncoding( - e360: asBool(json, '360'), - e480: asBool(json, '480'), - e720: asBool(json, '720'), - e1080: asBool(json, '1080'), - ); - - Map toJson() => { - '360': 360, - '480': 480, - '720': 720, - '1080': 1080, - }; -} diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index b608ba0c..5695479a 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -1,27 +1,17 @@ -import 'dart:convert'; -import 'dart:developer'; - import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/models/video_upload/platform_video_info.dart'; import 'package:acela/src/screens/drawer_screen/drawer_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_widgets.dart'; import 'package:acela/src/screens/search/search_screen.dart'; import 'package:acela/src/screens/upload/new_video_upload_screen.dart'; -import 'package:acela/src/screens/upload/upload_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/communicator.dart'; -import 'package:cross_file/cross_file.dart' show XFile; -import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; -import 'package:ffmpeg_kit_flutter/media_information_session.dart'; -import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' show get; import 'package:provider/provider.dart'; -import 'package:video_compress/video_compress.dart'; class HomeScreen extends StatefulWidget { const HomeScreen( @@ -162,82 +152,6 @@ class _HomeScreenState extends State { ); } - Widget _fab(HiveUserData user) { - if (isFabLoading) { - return FloatingActionButton( - onPressed: () {}, child: const CircularProgressIndicator()); - } - return FloatingActionButton( - onPressed: () async { - try { - setState(() { - isFabLoading = true; - }); - FilePickerResult? fileResult = - await FilePicker.platform.pickFiles(type: FileType.video); - - if (fileResult != null && fileResult.files.single.path != null) { - PlatformFile file = fileResult.files.single; - print(file.name); - print(file.bytes); - print(file.size); - print(file.extension); - print(file.path); - final compressInfo = await VideoCompress.compressVideo( - file.path!, - quality: VideoQuality.Res1280x720Quality, - deleteOrigin: false, - includeAudio: true, - ); - var fileSize = compressInfo?.filesize ?? file.size; - var sizeInMb = fileSize / 1000 / 1000; - if (sizeInMb > 500) { - throw 'Video is too big to be uploaded from mobile (exceeding 500 mb)'; - } - MediaInformationSession session = - await FFprobeKit.getMediaInformation( - compressInfo?.file?.path ?? file.path!); - var info = session.getMediaInformation(); - var duration = - (double.tryParse(info?.getDuration() ?? "0.0") ?? 0.0).toInt(); - log('Video duration is $duration'); - final xfile = XFile( - compressInfo?.file?.path ?? fileResult.files.single.path!); - var fileInfoInString = json.encode(PlatformVideoInfo( - duration: int.tryParse(info?.getDuration() ?? "0") ?? 0, - oFilename: xfile.name, - path: xfile.path, - size: fileSize) - .toJson()); - // change from here. - throw 'compression done'; - var cookie = await Communicator().getValidCookie(user); - log('Cookie is $cookie'); - var response = await Communicator() - .prepareVideo(user, fileInfoInString, cookie); - log('Response file name is ${response.filename}'); - setState(() { - isFabLoading = false; - log('Loading is set to false - $isLoading'); - var screen = - UploadScreen(videoId: response.video.id, xFile: xfile); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }); - } else { - throw 'User cancelled the video picker'; - } - } catch (e) { - showError(e.toString()); - setState(() { - isFabLoading = false; - }); - } - }, - child: const Icon(Icons.add), - ); - } - @override Widget build(BuildContext context) { var user = Provider.of(context); diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index b233ee89..c7ad6e26 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -31,9 +31,10 @@ class _VideoDetailsInfoState extends State { var isNsfwContent = false; var thumbIpfs = ''; var thumbUrl = ''; - var tags = ''; + var tags = 'threespeak,mobile'; var progress = 0.0; var processText = ''; + TextEditingController tagsController = TextEditingController(); void showError(String string) { var snackBar = SnackBar(content: Text('Error: $string')); @@ -45,6 +46,12 @@ class _VideoDetailsInfoState extends State { ScaffoldMessenger.of(context).showSnackBar(snackBar); } + @override + void initState() { + super.initState(); + tagsController.text = "threespeak,mobile"; + } + void initiateUpload( HiveUserData? data, XFile xFile, @@ -87,24 +94,24 @@ class _VideoDetailsInfoState extends State { }); try { // TO-DO change following to new video complete api - var videoUploadInfo = await Communicator().uploadComplete( + var v = await Communicator().newComplete( user: user, videoId: widget.item.id, - name: widget.ipfsName, title: widget.title, - description: widget.description, + description: widget.subtitle, isNsfwContent: isNsfwContent, tags: tags, - thumbnail: thumbIpfs, + thumbnail: thumbIpfs.isEmpty ? null : thumbIpfs, ); - print(videoUploadInfo.status); - showMessage('Video is uploaded & moved to encoding queue'); + // next publish on hive + // v.thumbUrl, + // thumbnail,videoV2,dDescription,dTitle,tags,author,permlink,duration,size,file,language,firstUpload, + // benes,beneWeights,postingKey + // next mark video as published setState(() { isCompleting = false; processText = ''; }); - Navigator.of(context).pop(); - Navigator.of(context).pop(); } catch (e) { showError(e.toString()); } @@ -140,9 +147,15 @@ class _VideoDetailsInfoState extends State { width: 320, height: 160, ) - : const Text( - 'Tap here to add thumbnail for your video\n\nThumbnail is MANDATORY to set.', - textAlign: TextAlign.center), + : widget.item.thumbUrl.isNotEmpty + ? Image.network( + widget.item.thumbUrl, + width: 320, + height: 160, + ) + : const Text( + 'Tap here to add thumbnail for your video\n\nThumbnail is MANDATORY to set.', + textAlign: TextAlign.center), ), onTap: () async { try { @@ -176,6 +189,7 @@ class _VideoDetailsInfoState extends State { return Container( margin: const EdgeInsets.all(10), child: TextField( + controller: tagsController, decoration: const InputDecoration( hintText: 'Comma separated tags', labelText: 'Tags', @@ -237,7 +251,7 @@ class _VideoDetailsInfoState extends State { ), floatingActionButton: isCompleting ? null - : thumbIpfs.isNotEmpty + : thumbIpfs.isNotEmpty || widget.item.thumbUrl.isNotEmpty ? FloatingActionButton( onPressed: () { if (user != null) { diff --git a/lib/src/screens/my_account/update_video/video_primary_info.dart b/lib/src/screens/my_account/update_video/video_primary_info.dart index cc127138..b951b972 100644 --- a/lib/src/screens/my_account/update_video/video_primary_info.dart +++ b/lib/src/screens/my_account/update_video/video_primary_info.dart @@ -1,4 +1,5 @@ import 'package:acela/src/models/video_details_model/video_details.dart'; +import 'package:acela/src/screens/my_account/update_video/video_details_info.dart'; import 'package:flutter/material.dart'; class VideoPrimaryInfo extends StatefulWidget { @@ -65,15 +66,13 @@ class _VideoPrimaryInfoState extends State { floatingActionButton: title.isNotEmpty && description.isNotEmpty ? FloatingActionButton( onPressed: () { - // var screen = UploadExtraScreen( - // videoId: widget.videoId, - // title: title, - // description: description, - // ipfsName: ipfsName, - // thumbUrl: thumbUrl, - // ); - // var route = MaterialPageRoute(builder: (c) => screen); - // Navigator.of(context).push(route); + var screen = VideoDetailsInfo( + item: widget.item, + title: title, + subtitle: description, + ); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); }, child: const Text('Next'), ) diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index dc6afa27..307a89b6 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -152,7 +152,7 @@ class _NewVideoUploadScreenState extends State { setState(() { didStartMoveToQueue = true; }); - var videoUploadInfo = await Communicator().newUploadComplete( + var videoUploadInfo = await Communicator().newUpload( user: user!, thumbnail: thumbName, oFilename: originalFileName, diff --git a/lib/src/screens/upload/upload_extra_screen.dart b/lib/src/screens/upload/upload_extra_screen.dart deleted file mode 100644 index 0783576b..00000000 --- a/lib/src/screens/upload/upload_extra_screen.dart +++ /dev/null @@ -1,258 +0,0 @@ -import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/utils/communicator.dart'; -import 'package:acela/src/widgets/loading_screen.dart'; -import 'package:cross_file/cross_file.dart' show XFile; -import 'package:file_picker/file_picker.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:tus_client/tus_client.dart'; - -class UploadExtraScreen extends StatefulWidget { - const UploadExtraScreen({ - Key? key, - required this.videoId, - required this.title, - required this.description, - required this.ipfsName, - required this.thumbUrl, - }) : super(key: key); - - final String videoId; - final String title; - final String description; - final String ipfsName; - final String? thumbUrl; - - @override - State createState() => _UploadExtraScreenState(); -} - -class _UploadExtraScreenState extends State { - var isCompleting = false; - var isPickingImage = false; - var uploadStarted = false; - var uploadComplete = false; - var isNsfwContent = false; - var thumbIpfs = ''; - var thumbUrl = ''; - var tags = ''; - var progress = 0.0; - var processText = ''; - - void showError(String string) { - var snackBar = SnackBar(content: Text('Error: $string')); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - - void showMessage(String string) { - var snackBar = SnackBar(content: Text('Message: $string')); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - - void initiateUpload( - HiveUserData? data, - XFile xFile, - ) async { - if (uploadStarted) return; - setState(() { - uploadStarted = true; - }); - final client = TusClient( - Uri.parse(Communicator.fsServer), - xFile, - store: TusMemoryStore(), - ); - await client.upload( - onComplete: () async { - print("Complete!"); - print(client.uploadUrl.toString()); - var url = client.uploadUrl.toString(); - var ipfsName = url.replaceAll("${Communicator.fsServer}/", ""); - setState(() { - thumbUrl = url; - thumbIpfs = ipfsName; - uploadComplete = true; - uploadStarted = false; - }); - }, - onProgress: (progress) { - print("Progress: $progress"); - setState(() { - this.progress = progress; - }); - }, - ); - } - - void completeVideo(HiveUserData user) async { - setState(() { - isCompleting = true; - processText = 'Updating video info'; - }); - try { - var videoUploadInfo = await Communicator().uploadComplete( - user: user, - videoId: widget.videoId, - name: widget.ipfsName, - title: widget.title, - description: widget.description, - isNsfwContent: isNsfwContent, - tags: tags, - thumbnail: thumbIpfs, - ); - print(videoUploadInfo.status); - showMessage('Video is uploaded & moved to encoding queue'); - setState(() { - isCompleting = false; - processText = ''; - }); - Navigator.of(context).pop(); - Navigator.of(context).pop(); - } catch (e) { - showError(e.toString()); - } - } - - Widget _thumbnailPicker(HiveUserData? user) { - return Center( - child: Container( - width: 320, - height: 160, - margin: EdgeInsets.all(10), - decoration: BoxDecoration( - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(24.0), - topRight: Radius.circular(24.0), - ), - boxShadow: [ - BoxShadow( - color: Colors.black12, - spreadRadius: 3, - blurRadius: 3, - ) - ]), - child: InkWell( - child: Center( - child: isPickingImage - ? const CircularProgressIndicator() - : progress > 0.0 && progress < 100.0 - ? CircularProgressIndicator(value: progress) - : thumbUrl.isNotEmpty - ? Image.network( - thumbUrl, - width: 320, - height: 160, - ) - : const Text( - 'Tap here to add thumbnail for your video\n\nThumbnail is MANDATORY to set.', - textAlign: TextAlign.center), - ), - onTap: () async { - try { - setState(() { - isPickingImage = true; - }); - FilePickerResult? fileResult = - await FilePicker.platform.pickFiles(type: FileType.image); - if (fileResult != null && fileResult.files.single.path != null) { - setState(() { - isPickingImage = false; - }); - final xfile = XFile(fileResult.files.single.path!); - initiateUpload(user, xfile); - } else { - throw 'User cancelled image picker'; - } - } catch (e) { - showError(e.toString()); - setState(() { - isPickingImage = false; - }); - } - }, - ), - ), - ); - } - - Widget _tagField() { - return Container( - margin: EdgeInsets.all(10), - child: TextField( - decoration: InputDecoration( - hintText: 'Comma separated tags', - labelText: 'Tags', - ), - onChanged: (text) { - setState(() { - tags = text; - }); - }, - maxLines: 1, - minLines: 1, - maxLength: 150, - ), - ); - } - - Widget _notSafe() { - return Container( - margin: EdgeInsets.all(10), - child: Row( - children: [ - const Text('Is this video NOT SAFE for work?'), - const Spacer(), - Switch( - value: isNsfwContent, - onChanged: (newVal) { - setState(() { - isNsfwContent = newVal; - }); - }, - ) - ], - ), - ); - } - - @override - Widget build(BuildContext context) { - var user = Provider.of(context); - if (user != null && thumbUrl.isEmpty && widget.thumbUrl != null) { - initiateUpload(user, XFile(widget.thumbUrl!)); - } - return Scaffold( - appBar: AppBar( - title: const Text('Provide more info'), - ), - body: isCompleting - ? Center( - child: LoadingScreen( - title: 'Please wait', - subtitle: processText, - ), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - _tagField(), - _notSafe(), - _thumbnailPicker(user), - const Text('Tap to change video thumbnail'), - ], - ), - floatingActionButton: isCompleting - ? null - : thumbIpfs.isNotEmpty - ? FloatingActionButton( - onPressed: () { - if (user != null) { - completeVideo(user); - } - }, - child: const Icon(Icons.save), - ) - : null, - ); - } -} diff --git a/lib/src/screens/upload/upload_screen.dart b/lib/src/screens/upload/upload_screen.dart deleted file mode 100644 index cb5032b7..00000000 --- a/lib/src/screens/upload/upload_screen.dart +++ /dev/null @@ -1,169 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/screens/upload/upload_extra_screen.dart'; -import 'package:acela/src/utils/communicator.dart'; -import 'package:cross_file/cross_file.dart' show XFile; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:tus_client/tus_client.dart'; -import 'package:video_thumbnail/video_thumbnail.dart'; - -class UploadScreen extends StatefulWidget { - const UploadScreen({ - Key? key, - required this.videoId, - required this.xFile, - }) : super(key: key); - - final String videoId; - final XFile xFile; - - @override - State createState() => _UploadScreenState(); -} - -class _UploadScreenState extends State { - void showError(String string) { - var snackBar = SnackBar(content: Text('Error: $string')); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - - void showMessage(String string) { - var snackBar = SnackBar(content: Text('Message: $string')); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - - var progress = 0.0; - var title = ''; - var description = ''; - var ipfsName = ''; - var uploadStarted = false; - var uploadComplete = false; - String? thumbUrl; - - @override - void initState() { - super.initState(); - Timer.periodic(Duration(seconds: 1), (timer) { - timer.cancel(); - initiateUpload(); - }); - } - - void initiateUpload() async { - if (uploadStarted) return; - setState(() { - uploadStarted = true; - }); - final client = TusClient( - Uri.parse(Communicator.fsServer), - widget.xFile, - store: TusMemoryStore(), - ); - await client.upload( - onComplete: () async { - print("Complete!"); - // Prints the uploaded file URL - print(client.uploadUrl.toString()); - var url = client.uploadUrl.toString(); - var ipfsName = url.replaceAll("${Communicator.fsServer}/", ""); - var pathImageThumb = await getThumbnail(widget.xFile.path); - setState(() { - this.ipfsName = ipfsName; - this.thumbUrl = pathImageThumb; - uploadComplete = true; - }); - }, - onProgress: (progress) { - print("Progress: $progress"); - setState(() { - this.progress = progress / 100.0; - }); - }, - ); - } - - Widget _body() { - return SafeArea( - child: Container( - margin: const EdgeInsets.all(20), - child: Column( - children: [ - Text('Upload Progress'), - SizedBox(height: 15), - LinearProgressIndicator(value: progress), - SizedBox(height: 15), - TextField( - decoration: InputDecoration( - hintText: 'Video title goes here', - labelText: 'Title', - ), - onChanged: (text) { - setState(() { - title = text; - }); - }, - maxLines: 1, - minLines: 1, - maxLength: 150, - ), - TextFormField( - decoration: InputDecoration( - hintText: 'Video description', - labelText: 'Description', - ), - onChanged: (text) { - setState(() { - description = text; - }); - }, - maxLines: 8, - minLines: 5, - ) - ], - ), - ), - ); - } - - Future getThumbnail(String path) async { - Directory tempDir = Directory.systemTemp; - var imagePath = await VideoThumbnail.thumbnailFile( - video: path, - thumbnailPath: tempDir.path, - imageFormat: ImageFormat.PNG, - maxWidth: 320, - quality: 100, - ); - return imagePath; - } - - @override - Widget build(BuildContext context) { - var user = Provider.of(context); - return Scaffold( - appBar: AppBar( - title: const Text('Video Info'), - ), - body: _body(), - floatingActionButton: user != null && uploadComplete && title.isNotEmpty - ? FloatingActionButton( - onPressed: () { - var screen = UploadExtraScreen( - videoId: widget.videoId, - title: title, - description: description, - ipfsName: ipfsName, - thumbUrl: thumbUrl, - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - child: Text('Next'), - ) - : null, - ); - } -} diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index fad10042..69122f6c 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -47,7 +47,7 @@ class Communicator { var key = HiveUserPostingKey.fromString(responseBody); return key.publicPostingKey; } else { - print(response.reasonPhrase); + log(response.reasonPhrase.toString()); throw response.reasonPhrase.toString(); } } @@ -201,7 +201,7 @@ class Communicator { } } - Future newUploadComplete({ + Future newUpload({ required HiveUserData user, required String thumbnail, required String oFilename, @@ -245,21 +245,19 @@ class Communicator { } } - Future uploadComplete({ + Future newComplete({ required HiveUserData user, required String videoId, - required String name, required String title, required String description, required bool isNsfwContent, required String tags, - required String thumbnail, + required String? thumbnail, }) async { var request = http.Request('POST', - Uri.parse('${Communicator.tsServer}/mobile/api/upload/complete')); + Uri.parse('${Communicator.tsServer}/mobile/api/upload/newComplete')); request.body = VideoUploadCompleteRequest( videoId: videoId, - filename: name, title: title, description: description, isNsfwContent: isNsfwContent, @@ -277,7 +275,7 @@ class Communicator { log("Successfully sent upload complete"); var string = await response.stream.bytesToString(); log('Video complete response is\n$string'); - return VideoUploadInfo.fromJsonString(string); + return VideoDetails.fromJsonString(string); } else { var string = await response.stream.bytesToString(); var error = ErrorResponse.fromJsonString(string).error ?? @@ -292,7 +290,7 @@ class Communicator { } Future> loadVideos(HiveUserData user) async { - print("Starting fetch videos ${DateTime.now().toIso8601String()}"); + log("Starting fetch videos ${DateTime.now().toIso8601String()}"); var cookie = await getValidCookie(user); var request = http.Request( 'GET', Uri.parse('${Communicator.tsServer}/mobile/api/my-videos')); @@ -301,8 +299,9 @@ class Communicator { http.StreamedResponse response = await request.send(); if (response.statusCode == 200) { var string = await response.stream.bytesToString(); + log('My videos response\n\n$string\n\n'); var videos = videoItemsFromString(string); - print("Ended fetch videos ${DateTime.now().toIso8601String()}"); + log("Ended fetch videos ${DateTime.now().toIso8601String()}"); return videos; } else { var string = await response.stream.bytesToString(); @@ -313,29 +312,6 @@ class Communicator { } } - Future loadOperations(HiveUserData user, String videoId) async { - var cookie = await getValidCookie(user); - var request = http.Request('POST', - Uri.parse('${Communicator.tsServer}/mobile/api/my-videos/operations')); - request.body = "{\"videoId\": \"$videoId\"}"; - Map map = { - "cookie": cookie, - "Content-Type": "application/json" - }; - request.headers.addAll(map); - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - var string = await response.stream.bytesToString(); - return string; - } else { - var string = await response.stream.bytesToString(); - var error = ErrorResponse.fromJsonString(string).error ?? - response.reasonPhrase.toString(); - log('Error from server is $error'); - throw error; - } - } - Future updatePublishState(HiveUserData user, String videoId) async { var cookie = await getValidCookie(user); var request = http.Request('POST', From d1eca02d56aefa5c94ee7f57227198075f740459 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 9 Aug 2022 02:45:14 +0530 Subject: [PATCH 110/466] video 1st level encoding. --- .flutter-plugins-dependencies | 2 +- .../upload/new_video_upload_screen.dart | 36 +++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index b7a12a62..d6b49e67 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-09 00:44:34.204612","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-09 02:41:34.867467","version":"3.0.4"} \ No newline at end of file diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index 307a89b6..86029345 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -89,19 +89,42 @@ class _NewVideoUploadScreenState extends State { log("path - ${file.path}"); // ---- Step 1. Select Video + // read video dimension + var probeSession = await FFprobeKit.execute( + "-i ${file.path!} -v quiet -show_entries stream=width,height -hide_banner"); + + var information = await probeSession.getLogsAsString(); + var data = information + .replaceAll("[STREAM]", "") + .replaceAll("[/STREAM]", "") + .replaceAll("[SIDE_DATA]", "") + .replaceAll("[/SIDE_DATA]", "") + .split("\n") + .where((e) => e.isNotEmpty); + var widthString = + data.firstWhere((e) => e.contains("width=")).split("=")[1]; + var heightString = + data.firstWhere((e) => e.contains("height=")).split("=")[1]; + int? width = int.parse(widthString); + int? height = int.parse(heightString); + // Step 2. Compress Video setState(() { didStartCompress = true; }); - final compressInfo = await VideoCompress.compressVideo( - file.path!, - quality: VideoQuality.Res640x480Quality, - deleteOrigin: false, - includeAudio: true, - ); + MediaInfo? compressInfo; + if (width != null && height != null && (width > 720 || height > 720)) { + compressInfo = await VideoCompress.compressVideo( + file.path!, + quality: VideoQuality.Res1280x720Quality, + deleteOrigin: false, + includeAudio: true, + ); + } setState(() { didCompress = true; }); + throw 'Stop for now'; // --- Step 2. Compress Video // Step 3. Video upload @@ -110,6 +133,7 @@ class _NewVideoUploadScreenState extends State { }); var fileSize = compressInfo?.filesize ?? file.size; var sizeInMb = fileSize / 1000 / 1000; + log("Compressed video file size in mb is - $sizeInMb"); if (sizeInMb > 500) { throw 'Video is too big to be uploaded from mobile (exceeding 500 mb)'; } From 54224467fbcbeb4558353cc8a4ad293b527ef898 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 9 Aug 2022 11:58:21 +0530 Subject: [PATCH 111/466] video work. --- .flutter-plugins | 5 +- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 48 ++++++-- .idea/libraries/Flutter_Plugins.xml | 5 +- .packages | 8 +- ios/Podfile.lock | 56 +-------- .../update_video/video_details_info.dart | 17 +-- .../upload/new_video_upload_screen.dart | 111 ++++++++++++++---- lib/src/utils/communicator.dart | 8 +- pubspec.lock | 42 +++++-- pubspec.yaml | 3 +- 11 files changed, 202 insertions(+), 103 deletions(-) diff --git a/.flutter-plugins b/.flutter-plugins index 1b043259..cec8e3aa 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -6,13 +6,16 @@ device_info_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartl device_info_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/ device_info_plus_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/ ffmpeg_kit_flutter=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/ -file_picker=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/ flutter_plugin_android_lifecycle=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/ flutter_secure_storage=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/ flutter_secure_storage_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/ flutter_secure_storage_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/ flutter_secure_storage_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/ flutter_secure_storage_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/ +image_picker=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker-0.8.5+3/ +image_picker_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_android-0.8.5+2/ +image_picker_for_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_for_web-2.1.8/ +image_picker_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_ios-0.8.5+6/ path_provider=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.11/ path_provider_android=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/ path_provider_ios=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index d6b49e67..81d0554e 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-09 02:41:34.867467","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_ios-0.8.5+6/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_android-0.8.5+2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"image_picker_for_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_for_web-2.1.8/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-09 11:53:36.416311","version":"3.0.4"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index cc4f6608..3ec751e7 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -310,13 +310,6 @@ - - - - - - @@ -492,6 +485,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1163,7 +1191,6 @@ - @@ -1186,6 +1213,11 @@ + + + + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 37e8f26e..c23ed354 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -23,7 +23,6 @@ - @@ -42,6 +41,10 @@ + + + + diff --git a/.packages b/.packages index 791d5a80..d6577d2c 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-08-05 01:54:35.079798. +# Generated by pub on 2022-08-09 11:43:40.207829. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-43.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.2/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.3.1/lib/ @@ -48,7 +48,6 @@ ffi:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffi- ffmpeg_kit_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/lib/ ffmpeg_kit_flutter_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter_platform_interface-0.2.1/lib/ file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib/ -file_picker:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/lib/ fixnum:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fixnum-1.0.1/lib/ flutter:file:///Applications/flutter/flutter/packages/flutter/lib/ flutter_dotenv:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_dotenv-5.0.2/lib/ @@ -74,6 +73,11 @@ html:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/htm http:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http-0.13.4/lib/ http_multi_server:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_multi_server-3.2.1/lib/ http_parser:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/http_parser-4.0.1/lib/ +image_picker:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker-0.8.5+3/lib/ +image_picker_android:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_android-0.8.5+2/lib/ +image_picker_for_web:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_for_web-2.1.8/lib/ +image_picker_ios:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_ios-0.8.5+6/lib/ +image_picker_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_platform_interface-2.6.1/lib/ intl:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/intl-0.17.0/lib/ io:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/io-1.0.3/lib/ js:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.4/lib/ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 481e00b8..a6a3e86b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -8,37 +8,6 @@ PODS: - Cache (6.0.0) - device_info_plus (0.0.1): - Flutter - - DKImagePickerController/Core (4.3.3): - - DKImagePickerController/ImageDataManager - - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.3) - - DKImagePickerController/PhotoGallery (4.3.3): - - DKImagePickerController/Core - - DKPhotoGallery - - DKImagePickerController/Resource (4.3.3) - - DKPhotoGallery (0.0.17): - - DKPhotoGallery/Core (= 0.0.17) - - DKPhotoGallery/Model (= 0.0.17) - - DKPhotoGallery/Preview (= 0.0.17) - - DKPhotoGallery/Resource (= 0.0.17) - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Core (0.0.17): - - DKPhotoGallery/Model - - DKPhotoGallery/Preview - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Model (0.0.17): - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Preview (0.0.17): - - DKPhotoGallery/Model - - DKPhotoGallery/Resource - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Resource (0.0.17): - - SDWebImage - - SwiftyGif - ffmpeg-kit-ios-https (4.5.1) - ffmpeg_kit_flutter (4.5.1): - ffmpeg_kit_flutter/https (= 4.5.1) @@ -46,9 +15,6 @@ PODS: - ffmpeg_kit_flutter/https (4.5.1): - ffmpeg-kit-ios-https (= 4.5.1) - Flutter - - file_picker (0.0.1): - - DKImagePickerController/PhotoGallery - - Flutter - Flutter (1.0.0) - flutter_secure_storage (3.3.1): - Flutter @@ -59,6 +25,8 @@ PODS: - HLSCachingReverseProxyServer (0.1.0): - GCDWebServer (~> 3.5) - PINCache (>= 3.0.1-beta.3) + - image_picker_ios (0.0.1): + - Flutter - libwebp (1.2.1): - libwebp/demux (= 1.2.1) - libwebp/mux (= 1.2.1) @@ -78,12 +46,8 @@ PODS: - PINCache/Core (3.0.3): - PINOperation (~> 1.2.1) - PINOperation (1.2.1) - - SDWebImage (5.12.5): - - SDWebImage/Core (= 5.12.5) - - SDWebImage/Core (5.12.5) - share_plus (0.0.1): - Flutter - - SwiftyGif (5.4.3) - url_launcher_ios (0.0.1): - Flutter - video_compress (0.3.0): @@ -102,10 +66,10 @@ DEPENDENCIES: - better_player (from `.symlinks/plugins/better_player/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - ffmpeg_kit_flutter (from `.symlinks/plugins/ffmpeg_kit_flutter/ios`) - - file_picker (from `.symlinks/plugins/file_picker/ios`) - Flutter (from `Flutter`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - FYVideoCompressor + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) @@ -118,8 +82,6 @@ DEPENDENCIES: SPEC REPOS: trunk: - Cache - - DKImagePickerController - - DKPhotoGallery - ffmpeg-kit-ios-https - FYVideoCompressor - GCDWebServer @@ -127,8 +89,6 @@ SPEC REPOS: - libwebp - PINCache - PINOperation - - SDWebImage - - SwiftyGif EXTERNAL SOURCES: better_player: @@ -137,12 +97,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/device_info_plus/ios" ffmpeg_kit_flutter: :path: ".symlinks/plugins/ffmpeg_kit_flutter/ios" - file_picker: - :path: ".symlinks/plugins/file_picker/ios" Flutter: :path: Flutter flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" path_provider_ios: :path: ".symlinks/plugins/path_provider_ios/ios" share_plus: @@ -164,23 +124,19 @@ SPEC CHECKSUMS: better_player: 2406bfe8175203c7a46fa15f9d778d73b12e1646 Cache: 4ca7e00363fca5455f26534e5607634c820ffc2d device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed - DKImagePickerController: 72fd378f244cef3d27288e0aebf217a4467e4012 - DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 ffmpeg-kit-ios-https: cec24d405b511e4f274980d8a9c751d384f89558 ffmpeg_kit_flutter: e2f0bd6b75e361faeee3b34c70650d3ec6ec35d0 - file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95 Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec FYVideoCompressor: 6d745d0b28432c6abacb234c3c1263755248136b GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4 HLSCachingReverseProxyServer: 59935e1e0244ad7f3375d75b5ef46e8eb26ab181 + image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20 - SDWebImage: 0905f1b7760fc8ac4198cae0036600d67478751e share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 - SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index c7ad6e26..156ef4a9 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -1,10 +1,11 @@ +import 'dart:developer'; + import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/loading_screen.dart'; -import 'package:cross_file/cross_file.dart' show XFile; -import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:provider/provider.dart'; import 'package:tus_client/tus_client.dart'; @@ -35,6 +36,7 @@ class _VideoDetailsInfoState extends State { var progress = 0.0; var processText = ''; TextEditingController tagsController = TextEditingController(); + final ImagePicker _picker = ImagePicker(); void showError(String string) { var snackBar = SnackBar(content: Text('Error: $string')); @@ -79,7 +81,7 @@ class _VideoDetailsInfoState extends State { }); }, onProgress: (progress) { - print("Progress: $progress"); + log("Progress: $progress"); setState(() { this.progress = progress; }); @@ -162,14 +164,13 @@ class _VideoDetailsInfoState extends State { setState(() { isPickingImage = true; }); - FilePickerResult? fileResult = - await FilePicker.platform.pickFiles(type: FileType.image); - if (fileResult != null && fileResult.files.single.path != null) { + final XFile? file = + await _picker.pickImage(source: ImageSource.gallery); + if (file != null) { setState(() { isPickingImage = false; }); - final xfile = XFile(fileResult.files.single.path!); - initiateUpload(user, xfile); + initiateUpload(user, file); } else { throw 'User cancelled image picker'; } diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index 86029345..8a7c7d32 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -4,11 +4,13 @@ import 'dart:io'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:cross_file/cross_file.dart' show XFile; import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; import 'package:ffmpeg_kit_flutter/media_information_session.dart'; -import 'package:file_picker/file_picker.dart'; +// import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:provider/provider.dart'; import 'package:tus_client/tus_client.dart'; import 'package:video_compress/video_compress.dart'; @@ -30,6 +32,14 @@ class _NewVideoUploadScreenState extends State { var didUploadThumbnail = false; var didMoveToQueue = false; + var timeShowFilePicker = '0.5 seconds'; + var timePickFile = ''; + var timeCompress = ''; + var timeUpload = ''; + var timeTakeDefaultThumbnail = ''; + var timeUploadThumbnail = ''; + var timeMoveToQueue = ''; + var didStartPickFile = false; var didStartCompress = false; var didStartUpload = false; @@ -42,6 +52,7 @@ class _NewVideoUploadScreenState extends State { var compressionProgress = 0.0; late Subscription _subscription; HiveUserData? user; + final ImagePicker _picker = ImagePicker(); @override void initState() { @@ -52,7 +63,7 @@ class _NewVideoUploadScreenState extends State { compressionProgress = progress; }); }); - Timer.periodic(const Duration(seconds: 1), (timer) { + Timer.periodic(const Duration(milliseconds: 500), (timer) { timer.cancel(); videoPickerFunction(); }); @@ -70,28 +81,25 @@ class _NewVideoUploadScreenState extends State { throw 'User not logged in'; } // Step 1. Select Video + var dateStartGettingVideo = DateTime.now(); setState(() { didStartPickFile = true; didShowFilePicker = true; }); - FilePickerResult? fileResult = - await FilePicker.platform.pickFiles(type: FileType.video); - if (fileResult != null && fileResult.files.single.path != null) { - setState(() { - didPickFile = true; - }); - PlatformFile file = fileResult.files.single; + + final XFile? file = await _picker.pickVideo(source: ImageSource.gallery); + if (file != null) { var originalFileName = file.name; - log(file.name); - log("bytes - ${file.bytes ?? 0}"); - log("size - ${file.size}"); - log("Extension - ${file.extension}"); + log(originalFileName); + // log("bytes - ${videoFile.bytes ?? 0}"); + // log("size - ${file.size}"); log("path - ${file.path}"); + var size = await file.length(); // ---- Step 1. Select Video // read video dimension var probeSession = await FFprobeKit.execute( - "-i ${file.path!} -v quiet -show_entries stream=width,height -hide_banner"); + "-i ${file.path} -v quiet -show_entries stream=width,height -hide_banner"); var information = await probeSession.getLogsAsString(); var data = information @@ -107,37 +115,47 @@ class _NewVideoUploadScreenState extends State { data.firstWhere((e) => e.contains("height=")).split("=")[1]; int? width = int.parse(widthString); int? height = int.parse(heightString); + var dateEndGettingVideo = DateTime.now(); + var diff = dateEndGettingVideo.difference(dateStartGettingVideo); + setState(() { + timePickFile = '${diff.inSeconds} seconds'; + didPickFile = true; + }); // Step 2. Compress Video + var dateStartProcessingVideo = DateTime.now(); setState(() { didStartCompress = true; }); MediaInfo? compressInfo; - if (width != null && height != null && (width > 720 || height > 720)) { + if (width != null && height != null && width > 720 && height > 720) { compressInfo = await VideoCompress.compressVideo( - file.path!, + file.path, quality: VideoQuality.Res1280x720Quality, deleteOrigin: false, includeAudio: true, ); } + var dateEndProcessingVideo = DateTime.now(); + diff = dateEndProcessingVideo.difference(dateStartProcessingVideo); setState(() { + timeCompress = '${diff.inSeconds} seconds'; didCompress = true; }); - throw 'Stop for now'; // --- Step 2. Compress Video // Step 3. Video upload + var dateStartUploadVideo = DateTime.now(); setState(() { didStartUpload = true; }); - var fileSize = compressInfo?.filesize ?? file.size; + var fileSize = compressInfo?.filesize ?? size; var sizeInMb = fileSize / 1000 / 1000; log("Compressed video file size in mb is - $sizeInMb"); if (sizeInMb > 500) { throw 'Video is too big to be uploaded from mobile (exceeding 500 mb)'; } - var path = compressInfo?.file?.path ?? file.path!; + var path = compressInfo?.file?.path ?? file.path; MediaInformationSession session = await FFprobeKit.getMediaInformation(path); var info = session.getMediaInformation(); @@ -145,34 +163,48 @@ class _NewVideoUploadScreenState extends State { (double.tryParse(info?.getDuration() ?? "0.0") ?? 0.0).toInt(); log('Video duration is $duration'); var name = await initiateUpload(path, false); + var dateEndUploadVideo = DateTime.now(); + diff = dateEndUploadVideo.difference(dateStartUploadVideo); setState(() { + timeUpload = '${diff.inSeconds} seconds'; didUpload = true; }); // --- Step 3. Video upload // Step 4. Generate Thumbnail + var dateStartTakingThumbnail = DateTime.now(); setState(() { didStartTakeDefaultThumbnail = true; }); var thumbPath = await getThumbnail(path); + var dateEndTakingThumbnail = DateTime.now(); + diff = dateEndTakingThumbnail.difference(dateStartTakingThumbnail); setState(() { + timeTakeDefaultThumbnail = '${diff.inSeconds} seconds'; didTakeDefaultThumbnail = true; }); // --- Step 4. Generate Thumbnail // Step 5. Upload Thumbnail + var dateStartUploadThumbnail = DateTime.now(); setState(() { didStartUploadThumbnail = true; }); var thumbName = await initiateUpload(thumbPath, true); + var dateEndUploadThumbnail = DateTime.now(); + diff = dateEndUploadThumbnail.difference(dateStartUploadThumbnail); setState(() { + timeUploadThumbnail = '${diff.inSeconds} seconds'; didUploadThumbnail = true; }); // --- Step 5. Upload Thumbnail log('Uploaded file name is $name'); log('Uploaded thumbnail file name is $thumbName'); + throw 'stop now'; + // Step 6. Move Video to Queue + var dateStartMoveToQueue = DateTime.now(); setState(() { didStartMoveToQueue = true; }); @@ -185,7 +217,10 @@ class _NewVideoUploadScreenState extends State { tusFileName: name, ); log(videoUploadInfo.status); + var dateEndMoveToQueue = DateTime.now(); + diff = dateEndMoveToQueue.difference(dateStartMoveToQueue); setState(() { + timeMoveToQueue = '${diff.inSeconds} seconds'; didMoveToQueue = true; showMessage('Video is uploaded & moved to encoding queue'); }); @@ -276,6 +311,25 @@ class _NewVideoUploadScreenState extends State { if (user != null && this.user == null) { this.user = user; } + var items = [ + timeShowFilePicker, + timePickFile, + timeCompress, + timeUpload, + timeTakeDefaultThumbnail, + timeUploadThumbnail, + timeMoveToQueue + ].where((e) => e.isNotEmpty); + var doubleItems = items + .map((e) => double.tryParse(e.replaceAll(" seconds", ""))) + .whereType() + .toList(); + var formatValue = doubleItems.isEmpty + ? 1.0 + : doubleItems.reduce((sum, element) { + return sum + element; + }); + var totalDuration = Utilities.formatTime(formatValue.toInt()); return Scaffold( appBar: AppBar( title: const Text('Video Upload Process'), @@ -283,16 +337,24 @@ class _NewVideoUploadScreenState extends State { body: ListView( children: [ ListTile( - title: const Text('Selecting & processing video'), + title: const Text('Launching Video Picker'), + trailing: didShowFilePicker + ? const Icon(Icons.check) + : const Icon(Icons.pending), + subtitle: didShowFilePicker ? Text(timeShowFilePicker) : null, + ), + ListTile( + title: const Text('Getting the Video'), trailing: !didPickFile ? !didStartPickFile ? const Icon(Icons.pending) : const CircularProgressIndicator() : const Icon(Icons.check), + subtitle: didPickFile ? Text(timePickFile) : null, ), ListTile( title: Text( - 'Compressing video (${didCompress ? 100.0 : compressionProgress.toStringAsFixed(2)}%)'), + 'Encoding video if needed (${didCompress ? 100.0 : compressionProgress.toStringAsFixed(2)}%)'), trailing: !didStartCompress ? const Icon(Icons.pending) : !didCompress @@ -302,6 +364,7 @@ class _NewVideoUploadScreenState extends State { value: compressionProgress / 100.0), ) : const Icon(Icons.check), + subtitle: didCompress ? Text(timeCompress) : null, ), ListTile( title: Text( @@ -314,15 +377,17 @@ class _NewVideoUploadScreenState extends State { child: LinearProgressIndicator(value: progress), ) : const Icon(Icons.check), + subtitle: didUpload ? Text(timeUpload) : null, ), ListTile( title: const Text('Taking video thumbnail'), - subtitle: const Text('You can edit thumbnail later'), trailing: !didStartTakeDefaultThumbnail ? const Icon(Icons.pending) : !didTakeDefaultThumbnail ? const CircularProgressIndicator() : const Icon(Icons.check), + subtitle: + didTakeDefaultThumbnail ? Text(timeTakeDefaultThumbnail) : null, ), ListTile( title: Text( @@ -336,6 +401,7 @@ class _NewVideoUploadScreenState extends State { value: thumbnailUploadProgress), ) : const Icon(Icons.check), + subtitle: didUploadThumbnail ? Text(timeUploadThumbnail) : null, ), ListTile( title: const Text('Move video to Encoding Queue'), @@ -344,6 +410,7 @@ class _NewVideoUploadScreenState extends State { : !didMoveToQueue ? const CircularProgressIndicator() : const Icon(Icons.check), + subtitle: didMoveToQueue ? Text(timeMoveToQueue) : null, ), ], ), diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 69122f6c..1db15401 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -26,8 +26,12 @@ class Communicator { // static const tsServer = "http://10.0.2.2:13050"; // iOS - static const tsServer = "http://localhost:13050"; - static const fsServer = "http://localhost:1080/files"; + // static const tsServer = "http://localhost:13050"; + // static const fsServer = "http://localhost:1080/files"; + + // iOS Device + static const tsServer = "http://192.168.1.8:13050"; + static const fsServer = "http://192.168.1.8:1080/files"; static const hiveApiUrl = 'https://api.hive.blog/'; diff --git a/pubspec.lock b/pubspec.lock index f70033ba..bfa4f0b1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -309,13 +309,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" - file_picker: - dependency: "direct main" - description: - name: file_picker - url: "https://pub.dartlang.org" - source: hosted - version: "4.6.1" fixnum: dependency: transitive description: @@ -485,6 +478,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.1" + image_picker: + dependency: "direct main" + description: + name: image_picker + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.5+3" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.5+2" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.8" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.5+6" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.6.1" intl: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 4fd95fe4..0a471c1b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: device_info_plus: ^4.0.0 elliptic: ^0.3.8 ffmpeg_kit_flutter: ^4.5.1 - file_picker: ^4.5.1 + # file_picker: ^4.5.1 flutter: sdk: flutter flutter_dotenv: ^5.0.2 @@ -62,6 +62,7 @@ dependencies: video_compress: ^3.1.0 video_thumbnail: ^0.5.0 webview_flutter: ^3.0.4 + image_picker: ^0.8.5+3 dev_dependencies: flutter_test: From 93cc5ad105c621aca0150059e887332f80d91722 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 9 Aug 2022 15:54:07 +0530 Subject: [PATCH 112/466] camera or photo gal --- .flutter-plugins | 1 + .flutter-plugins-dependencies | 2 +- .idea/Android-App.iml | 6 + .idea/libraries/Dart_Packages.xml | 8 ++ .idea/libraries/Flutter_Plugins.xml | 1 + .packages | 3 +- android/.idea/gradle.xml | 20 +-- android/.idea/modules.xml | 80 ++++++------ android/app/build.gradle | 2 +- android/build.gradle | 16 ++- .../gradle/wrapper/gradle-wrapper.properties | 2 +- ios/Podfile.lock | 50 ++++++++ lib/src/screens/home_screen/home_screen.dart | 29 ++++- .../upload/new_video_upload_screen.dart | 117 ++++++++---------- lib/src/utils/communicator.dart | 8 +- pubspec.lock | 7 ++ pubspec.yaml | 2 +- 17 files changed, 231 insertions(+), 123 deletions(-) diff --git a/.flutter-plugins b/.flutter-plugins index cec8e3aa..cb6d3d77 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -6,6 +6,7 @@ device_info_plus_macos=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartl device_info_plus_web=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/ device_info_plus_windows=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/ ffmpeg_kit_flutter=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/ +file_picker=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/ flutter_plugin_android_lifecycle=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/ flutter_secure_storage=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/ flutter_secure_storage_linux=/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 81d0554e..06a3a415 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_ios-0.8.5+6/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_android-0.8.5+2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"image_picker_for_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_for_web-2.1.8/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-09 11:53:36.416311","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_ios-0.8.5+6/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_android-0.8.5+2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"image_picker_for_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_for_web-2.1.8/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-09 15:46:26.615462","version":"3.0.4"} \ No newline at end of file diff --git a/.idea/Android-App.iml b/.idea/Android-App.iml index e065b41a..2337b2a4 100644 --- a/.idea/Android-App.iml +++ b/.idea/Android-App.iml @@ -98,6 +98,12 @@ + + + + + + diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 3ec751e7..9ef16747 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -310,6 +310,13 @@ + + + + + + @@ -1191,6 +1198,7 @@ + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index c23ed354..5f9089fd 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -45,6 +45,7 @@ + diff --git a/.packages b/.packages index d6577d2c..2fdd30ad 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-08-09 11:43:40.207829. +# Generated by pub on 2022-08-09 13:42:10.051853. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-43.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.2/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.3.1/lib/ @@ -48,6 +48,7 @@ ffi:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffi- ffmpeg_kit_flutter:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/lib/ ffmpeg_kit_flutter_platform_interface:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter_platform_interface-0.2.1/lib/ file:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib/ +file_picker:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/lib/ fixnum:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/fixnum-1.0.1/lib/ flutter:file:///Applications/flutter/flutter/packages/flutter/lib/ flutter_dotenv:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_dotenv-5.0.2/lib/ diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml index 0ace80cb..17674c7e 100644 --- a/android/.idea/gradle.xml +++ b/android/.idea/gradle.xml @@ -12,17 +12,19 @@ diff --git a/android/.idea/modules.xml b/android/.idea/modules.xml index 7e5c9e0b..a2fc6b9a 100644 --- a/android/.idea/modules.xml +++ b/android/.idea/modules.xml @@ -11,50 +11,58 @@ + + + + - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index ca43bad7..2a22a576 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -68,5 +68,5 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation platform('com.google.firebase:firebase-bom:29.0.4') implementation 'androidx.webkit:webkit:1.4.0' - implementation 'com.google.code.gson:gson:2.8.9' + implementation 'com.google.code.gson:gson:2.9.0' } diff --git a/android/build.gradle b/android/build.gradle index ecafd67a..7c89a319 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,9 +6,9 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.1.3' + classpath 'com.android.tools.build:gradle:7.2.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.google.gms:google-services:4.3.10' + classpath 'com.google.gms:google-services:4.3.13' } } @@ -30,3 +30,15 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +//rootProject.allprojects { +// subprojects { +// project.configurations.all { +// resolutionStrategy.eachDependency { details -> +// if (details.requested.group == 'androidx.core' && !details.requested.name.contains('androidx')) { +// details.useVersion "1.0.1" +// } +// } +// } +// } +//} diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index b73ad99e..7d176995 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a6a3e86b..90fbc1cc 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -8,6 +8,37 @@ PODS: - Cache (6.0.0) - device_info_plus (0.0.1): - Flutter + - DKImagePickerController/Core (4.3.4): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.4) + - DKImagePickerController/PhotoGallery (4.3.4): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.4) + - DKPhotoGallery (0.0.17): + - DKPhotoGallery/Core (= 0.0.17) + - DKPhotoGallery/Model (= 0.0.17) + - DKPhotoGallery/Preview (= 0.0.17) + - DKPhotoGallery/Resource (= 0.0.17) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.17): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.17): + - SDWebImage + - SwiftyGif - ffmpeg-kit-ios-https (4.5.1) - ffmpeg_kit_flutter (4.5.1): - ffmpeg_kit_flutter/https (= 4.5.1) @@ -15,6 +46,9 @@ PODS: - ffmpeg_kit_flutter/https (4.5.1): - ffmpeg-kit-ios-https (= 4.5.1) - Flutter + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter - Flutter (1.0.0) - flutter_secure_storage (3.3.1): - Flutter @@ -46,8 +80,12 @@ PODS: - PINCache/Core (3.0.3): - PINOperation (~> 1.2.1) - PINOperation (1.2.1) + - SDWebImage (5.13.2): + - SDWebImage/Core (= 5.13.2) + - SDWebImage/Core (5.13.2) - share_plus (0.0.1): - Flutter + - SwiftyGif (5.4.3) - url_launcher_ios (0.0.1): - Flutter - video_compress (0.3.0): @@ -66,6 +104,7 @@ DEPENDENCIES: - better_player (from `.symlinks/plugins/better_player/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - ffmpeg_kit_flutter (from `.symlinks/plugins/ffmpeg_kit_flutter/ios`) + - file_picker (from `.symlinks/plugins/file_picker/ios`) - Flutter (from `Flutter`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - FYVideoCompressor @@ -82,6 +121,8 @@ DEPENDENCIES: SPEC REPOS: trunk: - Cache + - DKImagePickerController + - DKPhotoGallery - ffmpeg-kit-ios-https - FYVideoCompressor - GCDWebServer @@ -89,6 +130,8 @@ SPEC REPOS: - libwebp - PINCache - PINOperation + - SDWebImage + - SwiftyGif EXTERNAL SOURCES: better_player: @@ -97,6 +140,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/device_info_plus/ios" ffmpeg_kit_flutter: :path: ".symlinks/plugins/ffmpeg_kit_flutter/ios" + file_picker: + :path: ".symlinks/plugins/file_picker/ios" Flutter: :path: Flutter flutter_secure_storage: @@ -124,8 +169,11 @@ SPEC CHECKSUMS: better_player: 2406bfe8175203c7a46fa15f9d778d73b12e1646 Cache: 4ca7e00363fca5455f26534e5607634c820ffc2d device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed + DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac + DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 ffmpeg-kit-ios-https: cec24d405b511e4f274980d8a9c751d384f89558 ffmpeg_kit_flutter: e2f0bd6b75e361faeee3b34c70650d3ec6ec35d0 + file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95 Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec FYVideoCompressor: 6d745d0b28432c6abacb234c3c1263755248136b @@ -136,7 +184,9 @@ SPEC CHECKSUMS: path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20 + SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 + SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 5695479a..ed695b90 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -9,6 +9,7 @@ import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/communicator.dart'; +import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' show get; import 'package:provider/provider.dart'; @@ -144,9 +145,31 @@ class _HomeScreenState extends State { Widget _fabNewUpload() { return FloatingActionButton( onPressed: () { - var screen = const NewVideoUploadScreen(); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); + showAdaptiveActionSheet( + context: context, + title: const Text('Select record type'), + androidBorderRadius: 30, + actions: [ + BottomSheetAction( + title: const Text('Camera'), + onPressed: (c) { + var screen = const NewVideoUploadScreen(camera: true); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).pop(); + Navigator.of(context).push(route); + }, + ), + BottomSheetAction( + title: const Text('Photo Gallery'), + onPressed: (c) { + var screen = const NewVideoUploadScreen(camera: false); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).pop(); + Navigator.of(context).push(route); + }), + ], + cancelAction: CancelAction(title: const Text('Cancel')), + ); }, child: const Icon(Icons.add), ); diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index 8a7c7d32..8746c19e 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -5,10 +5,8 @@ import 'dart:io'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; -import 'package:cross_file/cross_file.dart' show XFile; import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; import 'package:ffmpeg_kit_flutter/media_information_session.dart'; -// import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:provider/provider.dart'; @@ -17,7 +15,11 @@ import 'package:video_compress/video_compress.dart'; import 'package:video_thumbnail/video_thumbnail.dart'; class NewVideoUploadScreen extends StatefulWidget { - const NewVideoUploadScreen({Key? key}) : super(key: key); + const NewVideoUploadScreen({ + Key? key, + required this.camera, + }) : super(key: key); + final bool camera; @override State createState() => _NewVideoUploadScreenState(); @@ -26,7 +28,7 @@ class NewVideoUploadScreen extends StatefulWidget { class _NewVideoUploadScreenState extends State { var didShowFilePicker = false; var didPickFile = false; - var didCompress = false; + // var didCompress = false; var didUpload = false; var didTakeDefaultThumbnail = false; var didUploadThumbnail = false; @@ -34,14 +36,14 @@ class _NewVideoUploadScreenState extends State { var timeShowFilePicker = '0.5 seconds'; var timePickFile = ''; - var timeCompress = ''; + // var timeCompress = ''; var timeUpload = ''; var timeTakeDefaultThumbnail = ''; var timeUploadThumbnail = ''; var timeMoveToQueue = ''; var didStartPickFile = false; - var didStartCompress = false; + // var didStartCompress = false; var didStartUpload = false; var didStartTakeDefaultThumbnail = false; var didStartUploadThumbnail = false; @@ -87,34 +89,22 @@ class _NewVideoUploadScreenState extends State { didShowFilePicker = true; }); - final XFile? file = await _picker.pickVideo(source: ImageSource.gallery); + final XFile? file = await _picker.pickVideo( + source: widget.camera ? ImageSource.camera : ImageSource.gallery); if (file != null) { + setState(() { + didPickFile = true; + }); + var originalFileName = file.name; log(originalFileName); // log("bytes - ${videoFile.bytes ?? 0}"); // log("size - ${file.size}"); log("path - ${file.path}"); var size = await file.length(); + // var size = file.size; // ---- Step 1. Select Video - // read video dimension - var probeSession = await FFprobeKit.execute( - "-i ${file.path} -v quiet -show_entries stream=width,height -hide_banner"); - - var information = await probeSession.getLogsAsString(); - var data = information - .replaceAll("[STREAM]", "") - .replaceAll("[/STREAM]", "") - .replaceAll("[SIDE_DATA]", "") - .replaceAll("[/SIDE_DATA]", "") - .split("\n") - .where((e) => e.isNotEmpty); - var widthString = - data.firstWhere((e) => e.contains("width=")).split("=")[1]; - var heightString = - data.firstWhere((e) => e.contains("height=")).split("=")[1]; - int? width = int.parse(widthString); - int? height = int.parse(heightString); var dateEndGettingVideo = DateTime.now(); var diff = dateEndGettingVideo.difference(dateStartGettingVideo); setState(() { @@ -123,39 +113,41 @@ class _NewVideoUploadScreenState extends State { }); // Step 2. Compress Video - var dateStartProcessingVideo = DateTime.now(); - setState(() { - didStartCompress = true; - }); - MediaInfo? compressInfo; - if (width != null && height != null && width > 720 && height > 720) { - compressInfo = await VideoCompress.compressVideo( - file.path, - quality: VideoQuality.Res1280x720Quality, - deleteOrigin: false, - includeAudio: true, - ); - } - var dateEndProcessingVideo = DateTime.now(); - diff = dateEndProcessingVideo.difference(dateStartProcessingVideo); - setState(() { - timeCompress = '${diff.inSeconds} seconds'; - didCompress = true; - }); + // var dateStartProcessingVideo = DateTime.now(); + // setState(() { + // didStartCompress = true; + // }); + // MediaInfo? compressInfo; + // if (width != null && height != null && width > 720 && height > 720) { + // compressInfo = await VideoCompress.compressVideo( + // file.path!, + // quality: VideoQuality.Res1280x720Quality, + // deleteOrigin: false, + // includeAudio: true, + // ); + // } + // var dateEndProcessingVideo = DateTime.now(); + // diff = dateEndProcessingVideo.difference(dateStartProcessingVideo); + // setState(() { + // timeCompress = '${diff.inSeconds} seconds'; + // didCompress = true; + // }); // --- Step 2. Compress Video + // throw 'stop from here'; + // Step 3. Video upload var dateStartUploadVideo = DateTime.now(); setState(() { didStartUpload = true; }); - var fileSize = compressInfo?.filesize ?? size; + var fileSize = size; var sizeInMb = fileSize / 1000 / 1000; log("Compressed video file size in mb is - $sizeInMb"); if (sizeInMb > 500) { throw 'Video is too big to be uploaded from mobile (exceeding 500 mb)'; } - var path = compressInfo?.file?.path ?? file.path; + var path = file.path!; MediaInformationSession session = await FFprobeKit.getMediaInformation(path); var info = session.getMediaInformation(); @@ -201,8 +193,6 @@ class _NewVideoUploadScreenState extends State { log('Uploaded file name is $name'); log('Uploaded thumbnail file name is $thumbName'); - throw 'stop now'; - // Step 6. Move Video to Queue var dateStartMoveToQueue = DateTime.now(); setState(() { @@ -314,7 +304,6 @@ class _NewVideoUploadScreenState extends State { var items = [ timeShowFilePicker, timePickFile, - timeCompress, timeUpload, timeTakeDefaultThumbnail, timeUploadThumbnail, @@ -344,7 +333,7 @@ class _NewVideoUploadScreenState extends State { subtitle: didShowFilePicker ? Text(timeShowFilePicker) : null, ), ListTile( - title: const Text('Getting the Video'), + title: const Text('Getting/Compressing the Video'), trailing: !didPickFile ? !didStartPickFile ? const Icon(Icons.pending) @@ -352,20 +341,20 @@ class _NewVideoUploadScreenState extends State { : const Icon(Icons.check), subtitle: didPickFile ? Text(timePickFile) : null, ), - ListTile( - title: Text( - 'Encoding video if needed (${didCompress ? 100.0 : compressionProgress.toStringAsFixed(2)}%)'), - trailing: !didStartCompress - ? const Icon(Icons.pending) - : !didCompress - ? SizedBox( - width: 200, - child: LinearProgressIndicator( - value: compressionProgress / 100.0), - ) - : const Icon(Icons.check), - subtitle: didCompress ? Text(timeCompress) : null, - ), + // ListTile( + // title: Text( + // 'Encoding video if needed (${didCompress ? 100.0 : compressionProgress.toStringAsFixed(2)}%)'), + // trailing: !didStartCompress + // ? const Icon(Icons.pending) + // : !didCompress + // ? SizedBox( + // width: 200, + // child: LinearProgressIndicator( + // value: compressionProgress / 100.0), + // ) + // : const Icon(Icons.check), + // subtitle: didCompress ? Text(timeCompress) : null, + // ), ListTile( title: Text( 'Uploading video (${didUpload ? 100.0 : (progress * 100).toStringAsFixed(2)}%)'), diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 1db15401..68f9dc47 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -26,12 +26,12 @@ class Communicator { // static const tsServer = "http://10.0.2.2:13050"; // iOS - // static const tsServer = "http://localhost:13050"; - // static const fsServer = "http://localhost:1080/files"; + static const tsServer = "http://localhost:13050"; + static const fsServer = "http://localhost:1080/files"; // iOS Device - static const tsServer = "http://192.168.1.8:13050"; - static const fsServer = "http://192.168.1.8:1080/files"; + // static const tsServer = "http://192.168.1.8:13050"; + // static const fsServer = "http://192.168.1.8:1080/files"; static const hiveApiUrl = 'https://api.hive.blog/'; diff --git a/pubspec.lock b/pubspec.lock index bfa4f0b1..1120d4ed 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -309,6 +309,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" + file_picker: + dependency: "direct main" + description: + name: file_picker + url: "https://pub.dartlang.org" + source: hosted + version: "4.6.1" fixnum: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 0a471c1b..d0fc34c3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: device_info_plus: ^4.0.0 elliptic: ^0.3.8 ffmpeg_kit_flutter: ^4.5.1 - # file_picker: ^4.5.1 + file_picker: ^4.5.1 flutter: sdk: flutter flutter_dotenv: ^5.0.2 From 76aa82262711c6908966ac2b5cc24d57633b5550 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 9 Aug 2022 16:02:25 +0530 Subject: [PATCH 113/466] ready for demo. --- .flutter-plugins-dependencies | 2 +- .../upload/new_video_upload_screen.dart | 26 +------------------ lib/src/utils/communicator.dart | 8 +++--- 3 files changed, 6 insertions(+), 30 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 06a3a415..434f2fc5 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_ios-0.8.5+6/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_android-0.8.5+2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"image_picker_for_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_for_web-2.1.8/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-09 15:46:26.615462","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_ios-0.8.5+6/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_android-0.8.5+2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"image_picker_for_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_for_web-2.1.8/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-09 15:59:36.195515","version":"3.0.4"} \ No newline at end of file diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index 8746c19e..b81ee52b 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -112,30 +112,6 @@ class _NewVideoUploadScreenState extends State { didPickFile = true; }); - // Step 2. Compress Video - // var dateStartProcessingVideo = DateTime.now(); - // setState(() { - // didStartCompress = true; - // }); - // MediaInfo? compressInfo; - // if (width != null && height != null && width > 720 && height > 720) { - // compressInfo = await VideoCompress.compressVideo( - // file.path!, - // quality: VideoQuality.Res1280x720Quality, - // deleteOrigin: false, - // includeAudio: true, - // ); - // } - // var dateEndProcessingVideo = DateTime.now(); - // diff = dateEndProcessingVideo.difference(dateStartProcessingVideo); - // setState(() { - // timeCompress = '${diff.inSeconds} seconds'; - // didCompress = true; - // }); - // --- Step 2. Compress Video - - // throw 'stop from here'; - // Step 3. Video upload var dateStartUploadVideo = DateTime.now(); setState(() { @@ -147,7 +123,7 @@ class _NewVideoUploadScreenState extends State { if (sizeInMb > 500) { throw 'Video is too big to be uploaded from mobile (exceeding 500 mb)'; } - var path = file.path!; + var path = file.path; MediaInformationSession session = await FFprobeKit.getMediaInformation(path); var info = session.getMediaInformation(); diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 68f9dc47..1db15401 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -26,12 +26,12 @@ class Communicator { // static const tsServer = "http://10.0.2.2:13050"; // iOS - static const tsServer = "http://localhost:13050"; - static const fsServer = "http://localhost:1080/files"; + // static const tsServer = "http://localhost:13050"; + // static const fsServer = "http://localhost:1080/files"; // iOS Device - // static const tsServer = "http://192.168.1.8:13050"; - // static const fsServer = "http://192.168.1.8:1080/files"; + static const tsServer = "http://192.168.1.8:13050"; + static const fsServer = "http://192.168.1.8:1080/files"; static const hiveApiUrl = 'https://api.hive.blog/'; From ad0f322ed561e0ff10b5fc50c51726926fb5139f Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 11 Aug 2022 03:07:52 +0530 Subject: [PATCH 114/466] front-end changes. --- .flutter-plugins-dependencies | 2 +- android/app/src/main/assets/index.html | 363 +++++++++++++----- ios/Runner/Info.plist | 4 +- .../video_details_model/video_details.dart | 19 + .../video_upload_complete_request.dart | 21 +- .../update_video/video_details_info.dart | 25 +- .../upload/new_video_upload_screen.dart | 2 +- lib/src/utils/communicator.dart | 20 +- 8 files changed, 326 insertions(+), 130 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 434f2fc5..e0c599fe 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_ios-0.8.5+6/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_android-0.8.5+2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"image_picker_for_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_for_web-2.1.8/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-09 15:59:36.195515","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_ios-0.8.5+6/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_android-0.8.5+2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"image_picker_for_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_for_web-2.1.8/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-11 02:02:51.086712","version":"3.0.4"} \ No newline at end of file diff --git a/android/app/src/main/assets/index.html b/android/app/src/main/assets/index.html index fce39e2e..493569e8 100644 --- a/android/app/src/main/assets/index.html +++ b/android/app/src/main/assets/index.html @@ -15,104 +15,259 @@ function validateHiveKey(accountName, postingKey) { console.log("In here before async"); hive.api - .getAccountsAsync([accountName]) - .then(function (accounts) { - console.log("In here after async"); - console.log("Accounts: ", accounts); - const pubWif = accounts[0].posting.key_auths[0][0]; - console.log("PubWif: ", pubWif); - const Valid = hive.auth.wifIsValid(postingKey, pubWif); - console.log(`is valid ${Valid}`); - var result = { - type: "validateHiveKey", - valid: Valid, - accountName: accountName, - error: "", - }; - // window.webkit.messageHandlers.acela.postMessage(result); - Android.postMessage(JSON.stringify(result)); - }) - .catch(function (err) { - console.log("Error: ", err); - var result = { - type: "validateHiveKey", - valid: false, - accountName: accountName, - error: err.message, - }; - // window.webkit.messageHandlers.acela.postMessage(result); - Android.postMessage(JSON.stringify(result)); - }); + .getAccountsAsync([accountName]) + .then(function (accounts) { + console.log("In here after async"); + console.log("Accounts: ", accounts); + const pubWif = accounts[0].posting.key_auths[0][0]; + console.log("PubWif: ", pubWif); + const Valid = hive.auth.wifIsValid(postingKey, pubWif); + console.log(`is valid ${Valid}`); + var result = { + type: "validateHiveKey", + valid: Valid, + accountName: accountName, + error: "", + }; + // window.webkit.messageHandlers.acela.postMessage(result); + Android.postMessage(JSON.stringify(result)); + }) + .catch(function (err) { + console.log("Error: ", err); + var result = { + type: "validateHiveKey", + valid: false, + accountName: accountName, + error: err.message, + }; + // window.webkit.messageHandlers.acela.postMessage(result); + Android.postMessage(JSON.stringify(result)); + }); } function decryptMemo(accountName, postingKey, encrypted) { console.log("In here before async"); hive.api - .getAccountsAsync([accountName]) - .then(function (accounts) { - console.log("In here after async"); - console.log("Accounts: ", accounts); - const pubWif = accounts[0].posting.key_auths[0][0]; - console.log("PubWif: ", pubWif); - const Valid = hive.auth.wifIsValid(postingKey, pubWif); - console.log(`is valid ${Valid}`); - let decrypted = hive.memo.decode(postingKey, encrypted); - let result = { - type: "decryptedMemo", - accountName: accountName, - decrypted: decrypted, - error: "", - }; - // window.webkit.messageHandlers.acela.postMessage(result); - Android.postMessage(JSON.stringify(result)); - }) - .catch(function (err) { - console.log("Error: ", err); - let result = { - type: "decryptedMemo", - accountName: accountName, - decrypted: "", - error: err.message, - }; - // window.webkit.messageHandlers.acela.postMessage(result); - Android.postMessage(JSON.stringify(result)); + .getAccountsAsync([accountName]) + .then(function (accounts) { + console.log("In here after async"); + console.log("Accounts: ", accounts); + const pubWif = accounts[0].posting.key_auths[0][0]; + console.log("PubWif: ", pubWif); + const Valid = hive.auth.wifIsValid(postingKey, pubWif); + console.log(`is valid ${Valid}`); + let decrypted = hive.memo.decode(postingKey, encrypted); + let result = { + type: "decryptedMemo", + accountName: accountName, + decrypted: decrypted, + error: "", + }; + // window.webkit.messageHandlers.acela.postMessage(result); + Android.postMessage(JSON.stringify(result)); + }) + .catch(function (err) { + console.log("Error: ", err); + let result = { + type: "decryptedMemo", + accountName: accountName, + decrypted: "", + error: err.message, + }; + // window.webkit.messageHandlers.acela.postMessage(result); + Android.postMessage(JSON.stringify(result)); + }); + } + + function processTags(tags) { + const fallback = ["threespeak", "video"]; + const processed = []; + for (let tag of tags) { + tag = tag.toLowerCase().trim(); + if (!tag.startsWith("hive-") && tag.length >= 3) { + tag = tag.replace(/[^a-z0-9]/g, ""); + if (!processed.includes(tag) && tag.length >= 3) { + processed.push(tag); + } + } + } + return processed.length === 0 ? fallback : processed; + } + + function customStringEscaping(string) { + return string.split("'").join("’").split('"').join("“"); + } + + function buildJSONMetadata(thumbnail,videoV2,description,title,tags,author,permlink,duration,size,file,language,firstUpload,cdn) { + // 2. set the sourceMap + const sourceMap = []; + if (videoV2 !== undefined) { + sourceMap.push({ + type: "video", + url: videoV2, + format: "m3u8", }); + } + let escapedVideoDescription = customStringEscaping(description); + let escapedVideoTitle = customStringEscaping(title); + return { + tags: processTags(tags.split(",")), + app: "3speak/0.3.0", + type: "3speak/video", + image: [thumbnail], + video: { + info: { + platform: "3speak", + title: escapedVideoTitle, + author: author, + permlink: permlink, + duration: duration, + filesize: size, + file: file, + lang: language, + firstUpload: firstUpload, + video_v2: videoV2, + sourceMap: [ + ...sourceMap, + { + type: "thumbnail", + url: thumbnail, + }, + ], + }, + content: { + description: escapedVideoDescription, + tags: processTags(tags.split(",")), + }, + }, + }; } - function renderTemplate(video) { - const PostTemplate = `


[![](@@@thumbnail@@@)](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)

[Watch on 3Speak](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)



---

@@@description@@@

---

[3Speak](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)
`; - return PostTemplate.replace(/@@@thumbnail@@@/g, video.baseThumbUrl) - .replace(/@@@author@@@/g, video.owner) - .replace(/@@@permlink@@@/g, video.permlink) - .replace(/@@@description@@@/g, video.description); + function renderTemplate(baseThumbUrl,owner,permlink,description) { + const PostTemplate = `

[![](@@@thumbnail@@@)](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)

[Watch on 3Speak](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)



---

@@@description@@@

---

[3Speak](https://3speak.tv/watch?v=@@@author@@@/@@@permlink@@@)
`; + return PostTemplate.replace(/@@@thumbnail@@@/g, baseThumbUrl) + .replace(/@@@author@@@/g, owner) + .replace(/@@@permlink@@@/g, permlink) + .replace(/@@@description@@@/g, description); } - function postVideo(data, postingKey) { - console.log(`Response received from server: ${data}`); - const bdata = atob(data); - const result = JSON.parse(bdata).data; - const json_metadata = JSON.stringify(result.json_metadata); - const video = result.videoBody; - let comment = { ...result.comment, json_metadata: json_metadata }; - comment.body = renderTemplate(video); - const newExtensions = result.extensions.sort((a, b) => { - let fa = a.account.toLowerCase(), - fb = b.account.toLowerCase(); - if (fa < fb) return -1; - if (fa > fb) return 1; - return 0; - }); - const comment_options = { - ...result.comment_options, - extensions: [[0, { beneficiaries: newExtensions }]], + function videoObjectForBody(description, thumbnail, owner, permlink) { + let escapedVideoDescription = customStringEscaping(description); + return { + baseThumbUrl: thumbnail, + owner: owner, + permlink: permlink, + description: escapedVideoDescription, }; - const json = JSON.stringify(result.custom_json.json); - const custom_json = { ...result.custom_json, json: json }; - const ops = [ - ["comment", comment], - ["comment_options", comment_options], - ["custom_json", custom_json], + } + + function buildPublishCustomJson(owner,permlink,language,duration,title) { + return ['custom_json', { + required_posting_auths: ['threespeak', owner], + required_auths: [], + id: '3speak-publish', + json: JSON.stringify({ + author: owner, + permlink: permlink, + category: 'general', + language: language, + duration: duration, + title: title + }) + }]; + } + + async function hivePostExist(author, permlink) { + try { + let content = await hive.api.getContentAsync(author, permlink); + + //Apparently Hive API returns a string when post is empty and object when post exists! :shrug: + if (typeof content === "string") { + return JSON.parse(content).result.length !== 0; + } else { + //Just to be sure there is actual content + return !!content.body; + } + } catch (e) { + console.log(e); + return false; + } + } + + function newPostVideo(thumbnail,videoV2,dDescription,dTitle,tags,author,permlink,duration,size,file,language,firstUpload,benes,beneWeights,postingKey) { + let result = await hivePostExist(author,permlink); + if (result) { + var newResult = { + type: "postVideo", + valid: true, + error: "success", + }; + window.webkit.messageHandlers.acela.postMessage(result); + return; + } + let description = atob(dDescription); + description = decodeURIComponent(escape(description)); + let title = atob(dTitle); + title = decodeURIComponent(escape(title)); + let jsonMetaData = buildJSONMetadata(thumbnail,videoV2,description,title,tags,author,permlink,duration,size,file,language,firstUpload); + let customJson = buildPublishCustomJson(author,permlink,language,duration,title); + let newBen = [ + { account: "threespeakleader", weight: 100 }, + { account: "spk.beneficiary", weight: 850 }, ]; + let [account] = await hive.api.getAccountsAsync([author]); + if (account && account.json_metadata) { + let json = JSON.parse(account.json_metadata); + if (json.beneficiaries) { + if (Array.isArray(json.beneficiaries)) { + let benefactors = json.beneficiaries + .filter((x) => x.name !== "spk.delegation") + .filter((x) => x.name && x.label); + for (let bene of benefactors) { + switch (bene.label) { + case "referrer": + newBen.push({ account: bene.name, weight: bene.weight }); + break; + case "provider": + newBen.push({ account: bene.name, weight: bene.weight }); + break; + case "creator": + newBen.push({ account: bene.name, weight: bene.weight }); + break; + } + } + } + } + } + benes.split(",").forEach((string, index) => { + const value = parseInt(beneWeights.split(",")[index]); + newBen.push({ account: string, weight: value }); + }); + let benefactor_global = [[0, {beneficiaries: newBen}]]; + let comment_options = ['comment_options', { + author: author, + permlink: permlink, + allow_votes: true, + allow_curation_rewards: true, + extensions: benefactor_global + }]; + let videoObject = videoObjectForBody(description, thumbnail, author, permlink); + let body = renderTemplate(videoObject.baseThumbUrl,videoObject.owner,videoObject.permlink,videoObject.description); + hive.broadcast.updateOperations(); + const operations = []; + operations.push([ + 'comment', { + parent_author: '', + parent_permlink: 'hive-181335', + author: author, + permlink: permlink, + title: title.substr(0, 254), + body: body, + json_metadata: JSON.stringify(jsonMetaData) + } + ]); + operations.push(comment_options); + operations.push(customJson); console.log(`ops is ${ops}`); async function tryPublish(operations, key) { try { @@ -121,25 +276,25 @@ return e; } } - tryPublish(ops, postingKey) - .then((result) => { - var newResult = { - type: "postVideo", - valid: true, - error: JSON.stringify(result), - }; - // window.webkit.messageHandlers.acela.postMessage(result); - Android.postMessage(JSON.stringify(newResult)); + tryPublish(operations, postingKey) + .then((result) => { + var newResult = { + type: "postVideo", + valid: true, + error: "success", + }; + //window.webkit.messageHandlers.acela.postMessage(result); + Android.postMessage(JSON.stringify(newResult)); }) - .catch((error) => { - console.error(error); - var result = { - type: "postVideo", - valid: false, - error: error.message, - }; - // window.webkit.messageHandlers.acela.postMessage(result); - Android.postMessage(JSON.stringify(result)); + .catch((error) => { + console.error(error); + var result = { + type: "postVideo", + valid: false, + error: error.message, + }; + // window.webkit.messageHandlers.acela.postMessage(result); + Android.postMessage(JSON.stringify(result)); }); } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index acfbc098..9b93b7fe 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -36,7 +36,7 @@ NSAppleMusicUsageDescription Allow access to music NSCameraUsageDescription - Allow access to videos + Allow access to camera to capture the video NSPhotoLibraryUsageDescription Allow access to videos UIBackgroundModes @@ -66,5 +66,7 @@ UIViewControllerBasedStatusBarAppearance + NSMicrophoneUsageDescription + Allow access to microphone while capturing the video diff --git a/lib/src/models/video_details_model/video_details.dart b/lib/src/models/video_details_model/video_details.dart index b8c21040..384bd874 100644 --- a/lib/src/models/video_details_model/video_details.dart +++ b/lib/src/models/video_details_model/video_details.dart @@ -64,6 +64,25 @@ class VideoDetails { factory VideoDetails.fromJsonString(String jsonString) => VideoDetails.fromJson(json.decode(jsonString)); + List get benes { + if (beneficiaries == "[]") { + return ["sagarkothari88", "100"]; + } else { + try { + var array = json.decode(beneficiaries) as List; + var list = array.map((e) => e['account']).toList(); + var amounts = array.map((e) => e['weight']).toList(); + if (!list.contains('sagarkothari88')) { + list.add('sagarkothari88'); + amounts.add('100'); + } + return [list.join(","), amounts.join(",")]; + } catch (e) { + return ["sagarkothari88", "100"]; + } + } + } + factory VideoDetails.fromJson(Map? json) => VideoDetails( created: asString(json, 'created'), paid: asBool(json, 'paid'), diff --git a/lib/src/models/video_upload/video_upload_complete_request.dart b/lib/src/models/video_upload/video_upload_complete_request.dart index 26e80423..9598b9cf 100644 --- a/lib/src/models/video_upload/video_upload_complete_request.dart +++ b/lib/src/models/video_upload/video_upload_complete_request.dart @@ -17,14 +17,19 @@ class VideoUploadCompleteRequest { required this.thumbnail, }); - Map toJson() => { - 'videoId': videoId, - 'title': title, - 'description': description, - 'isNsfwContent': isNsfwContent, - 'tags': tags, - 'thumbnail': thumbnail - }; + Map toJson() { + var map = { + 'videoId': videoId, + 'title': title, + 'description': description, + 'isNsfwContent': isNsfwContent, + 'tags': tags, + }; + if (thumbnail != null && thumbnail!.isNotEmpty) { + map['thumbnail'] = thumbnail!; + } + return map; + } String toJsonString() => json.encode(toJson()); } diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index 156ef4a9..389d36b9 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -96,7 +96,7 @@ class _VideoDetailsInfoState extends State { }); try { // TO-DO change following to new video complete api - var v = await Communicator().newComplete( + var v = await Communicator().updateInfo( user: user, videoId: widget.item.id, title: widget.title, @@ -105,11 +105,26 @@ class _VideoDetailsInfoState extends State { tags: tags, thumbnail: thumbIpfs.isEmpty ? null : thumbIpfs, ); + log('Benes are ${v.benes}'); + // v.thumbUrl + // v.video_v2 + // v.description to encode + // v.title to encode + // v.tags + // user.username + // v.permlink + // v.duration + // v.size + // v.originalFilename + // "en" + // v.firstUpload + // v.benes[0] + // v.benes[1] + // postingKey + // next publish on hive - // v.thumbUrl, - // thumbnail,videoV2,dDescription,dTitle,tags,author,permlink,duration,size,file,language,firstUpload, - // benes,beneWeights,postingKey - // next mark video as published + // newPostVideo(thumbnail,videoV2,dDescription,dTitle,tags,author,permlink, + // duration,size,file,language,firstUpload,benes,beneWeights,postingKey setState(() { isCompleting = false; processText = ''; diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index b81ee52b..a51fe34e 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -174,7 +174,7 @@ class _NewVideoUploadScreenState extends State { setState(() { didStartMoveToQueue = true; }); - var videoUploadInfo = await Communicator().newUpload( + var videoUploadInfo = await Communicator().uploadInfo( user: user!, thumbnail: thumbName, oFilename: originalFileName, diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 1db15401..8aab7d63 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -22,16 +22,16 @@ class Communicator { // static const fsServer = "https://uploads.3speak.tv/files"; // Android - // static const fsServer = "http://10.0.2.2:1080/files"; - // static const tsServer = "http://10.0.2.2:13050"; + static const fsServer = "http://10.0.2.2:1080/files"; + static const tsServer = "http://10.0.2.2:13050"; // iOS // static const tsServer = "http://localhost:13050"; // static const fsServer = "http://localhost:1080/files"; // iOS Device - static const tsServer = "http://192.168.1.8:13050"; - static const fsServer = "http://192.168.1.8:1080/files"; + // static const tsServer = "http://192.168.1.8:13050"; + // static const fsServer = "http://192.168.1.8:1080/files"; static const hiveApiUrl = 'https://api.hive.blog/'; @@ -205,7 +205,7 @@ class Communicator { } } - Future newUpload({ + Future uploadInfo({ required HiveUserData user, required String thumbnail, required String oFilename, @@ -214,8 +214,8 @@ class Communicator { required String tusFileName, }) async { var cookie = await getValidCookie(user); - var request = http.Request('POST', - Uri.parse('${Communicator.tsServer}/mobile/api/upload/newUpload')); + var request = http.Request( + 'POST', Uri.parse('${Communicator.tsServer}/mobile/api/upload_info')); request.body = NewVideoUploadCompleteRequest( size: size, thumbnail: thumbnail, @@ -249,7 +249,7 @@ class Communicator { } } - Future newComplete({ + Future updateInfo({ required HiveUserData user, required String videoId, required String title, @@ -258,8 +258,8 @@ class Communicator { required String tags, required String? thumbnail, }) async { - var request = http.Request('POST', - Uri.parse('${Communicator.tsServer}/mobile/api/upload/newComplete')); + var request = http.Request( + 'POST', Uri.parse('${Communicator.tsServer}/mobile/api/update_info')); request.body = VideoUploadCompleteRequest( videoId: videoId, title: title, From d84a361cf878b7622b4a73444196fa2289b96412 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sat, 13 Aug 2022 03:21:21 +0530 Subject: [PATCH 115/466] publishing on hive works, --- .flutter-plugins-dependencies | 2 +- .idea/libraries/Dart_Packages.xml | 1324 ----------------- .idea/libraries/Flutter_Plugins.xml | 52 +- .packages | 2 +- android/.idea/gradle.xml | 6 +- android/.idea/modules.xml | 4 + android/app/src/main/assets/index.html | 51 +- .../kotlin/com/example/acela/MainActivity.kt | 23 +- ios/Runner/public/index.html | 2 +- .../video_details_model/video_details.dart | 15 + .../update_video/video_details_info.dart | 26 +- lib/src/utils/communicator.dart | 1 + 12 files changed, 115 insertions(+), 1393 deletions(-) delete mode 100644 .idea/libraries/Dart_Packages.xml diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index e0c599fe..a0920183 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_ios-0.8.5+6/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_android-0.8.5+2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"image_picker_for_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_for_web-2.1.8/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-11 02:02:51.086712","version":"3.0.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_ios-0.8.5+6/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_avfoundation-2.3.5/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus-4.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-5.0.2/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_android-0.8.5+2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"path_provider_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.17/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus-4.0.10/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_android-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_thumbnail-0.5.2/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_android-2.9.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_macos-2.2.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_macos-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_compress-3.1.1/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_linux-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_linux-1.1.0/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_windows-2.1.1/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.0.7/","native_build":false,"dependencies":[]},{"name":"share_plus_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_plus_web-2.1.0/","dependencies":[]},{"name":"file_picker","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-4.6.1/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"image_picker_for_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker_for_web-2.1.8/","dependencies":[]},{"name":"share_plus_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/share_plus_web-3.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/","dependencies":[]},{"name":"video_player_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/video_player_web_hls-0.1.11+4/","dependencies":[]},{"name":"wakelock_web","path":"/Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-08-13 02:19:49.773067","version":"3.0.4"} \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml deleted file mode 100644 index 9ef16747..00000000 --- a/.idea/libraries/Dart_Packages.xml +++ /dev/null @@ -1,1324 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 5f9089fd..da4cba08 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,51 +1,51 @@ - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - + - - - - + - + diff --git a/.packages b/.packages index 2fdd30ad..9db2f06e 100644 --- a/.packages +++ b/.packages @@ -3,7 +3,7 @@ # # For more info see: https://dart.dev/go/dot-packages-deprecation # -# Generated by pub on 2022-08-09 13:42:10.051853. +# Generated by pub on 2022-08-13 02:11:55.587605. _fe_analyzer_shared:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-43.0.0/lib/ adaptive_action_sheet:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_action_sheet-2.0.2/lib/ analyzer:file:///Applications/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-4.3.1/lib/ diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml index 17674c7e..3b4c30d2 100644 --- a/android/.idea/gradle.xml +++ b/android/.idea/gradle.xml @@ -1,6 +1,5 @@ -
{(SRC+sy;0j3sLFezro!7InHJ}54fqXTTOZNPr5 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�cn| zIi|YU!_x~x&G6?hxch)7Y{F>S@VsqC{#lKYZ+G_s_6C(OS)FfXP;W0Uw9~J<=1-Zv zXOE4O1{*wX&O_D^u1le2CIq--p3GcL1q1|X7`=!fdA@2 zt$d$2&W$^)CBgg^>p;D5sM_;hgE8lI>>Ls&xfUZGlA6jblA|WX)Z3ITbq4op1y#1- zgMVTRF235H`^L9z=eB1pucgTr)l{&Ek6{Ny0(}tOK7H(4CbQ6klyV)^y8_`1d5bF) zs5I=1$03IJ({&bPPxTO5KWm6jS6S~u+c-Y!r?AZK{oyU_Xk(LxP>4r*EE&7bn&Grz z=i$PaTxo3n_#Tg@G>lfxDa~MbViJlEJ($8}JsTeXg>$dwmgFsJ_~GZtz(HvV@kAVS zj9AI#r8=kdJqN8F$!8B!^gO!_PIGq?llf$&>(r$nh`ns_+}Gb_P3)(?ck4EL0G+!% zBq}{h7Zz$r*5RD3WKhUenMT=5ue8-)|D>(`yFawV6{~G~qSJP@H>MrPmEir;aOvR% zaVRLk+=c+BXtz>mfv5}`=F`N}x%lZVTObt5Mfo}rpWZBwd+GuHs=KZ|=q3vo0f%)K zGI!nepl!PQL56#FxUr=yw2{6S5p8F4NLe*b`d)hNN1!vZayX^ocyOR&Rv=V98(?Eb zJ{~W!8Zr=}AtR7fTr>yN*?SysS#getLiAY0)}zsa8a*qEbQBRcy&L1Rbi5;7g!G-~ z_e5DB0_bkR38K)4(tIBtikivkR(zE2@9ML%ntHEJPgkcEmSdw5oy0=+5;tLFd6q{1 zXEsXwj`#AYyK1KMe0y_t%+o4(U zM3fO%s)pRqmM@@z*|npUX>Fn8l?I4GE{A>>N)pvn=?)L0#~&VR?0cmwd<*G#9^7bk zvWKU7UkL5eu9y9w?wy;qWc}$ba(B(`@&rSrF>3>;Gt!==u z-S*aITV7LRuUfUjjU8(o5hv;$0Yop5Go(EHI2FKY=EFK%y}%Y}3+K$e*x7iNR1VK(r~aLrwtG zVMI>xo3Wm!KRn_^3Q*Dv{GP zX-RbvwPB{Ad8mE2D4cKp(wFVgyMJw0zV21F=#{TvMS2PI4BlyH4@{Q66~c_w&9a|| z&K}~2^F-h+G9?mLV#n$v5feSwP4pc%!|~ih9ILeXsOX zg^;cgK)c(qg=8BWy6w5`n=Mf`3%MuC#~Q`qz#^}aL`a8-c!pbfP0)7D6omA?J-cjM zXPaHL>@+*4x|jtiHY$;^X7YJZREJln2;A&|EI5Jipg)BQz>P>)NPoJ|DpSw^(L$O^ z69sfYDT?^cXAZR4&fZolD2z86#4)DwB*N(neF6hP?X6EyeChK?vrU1&_kah(V`wpvRW4J=@NC*)^}tn>#0> zve_9-(e-F$pQ5D4PDa4d;Rus;&IVfM>lm9d4^D_HEf~ugn$JC$((eD(x9zd-e9x9b zp60_TtU{hxbLg=B`d|Kkd*VYMFuUtlk^gq*RB2Cf6CxO)dOBwx+^TW18%T(xV=^J6 z7qZeWqZS7BUAVaX^^;HFkKLDp;3S!*L)buA70a(3@D1!0ugc-l%_;ojw;-{ zk_J}!e|_VRZQF)T>>w^>@MZdrC<+O?A3bb)?PkYO6U&+}|J^tKCcl36U0F#@`K7nZ zl&3mQg2+6X^noNC3Fd@28y!YWg&@KpB{H4ZI!+_jjkaNVGY%nNH9Dat5`#yE4ISuuv4;L1O@(I_9uN9CfpKnW(wtt)}vCtSe)Jo&iQmzUTYyh|>_KT;*d zD^dX<&8rC@|0cYoPcJKZ_4VByM%vuk}4$qr7g2T~U z7kh~n29ZO$B^$px(vRvK$AOUg>M;a(0PK>-q%K4p2cF$%&*5MGB0PK6l@wT&PurvF zDo4f~-w@@5bXrkFLm&!(R7v0e`0x@kY7dedS}Hv|d)-mo8jl4ULVMV1O}^NkxKo#K~hoCm-GL_BZ~zc=^2V z`HN}($vFXy;WTEo5}LCLL3|}P$C#ql8{TPk@8#hvq9BLlZLPNXv!AmKx87p4Ox25n z#d2+992T6W(izkN3LqpU43pJmxY?C?t>#W^xc?D*V%@XW{evG{#mZ$?ebySQMHQ$d z5YvV8na1hdw2=%u1cH8mvvsPPL zWT!8jXY;BnYyqqOQic{W6?3nus=VqRs!ld%#_fcI(p3;V9CY!u?(r7ong~zt++mMw z-D6F_L`zEIJ{4Kz&^OZ-9Cm`4R@;O#gI0+l7Yss0K{`4r#Hkdr0IK$uSSdX6wt~sD zmJa*oKYh{~u{J-4z9ZYQ68+>MGarO-3itGlv?Z2ZdVa@Q?|9X#rhDohnjkbyxX;O1 zoxu-s6M+fW%G^0nzYszPl@dM33WC;DBa(X1D50yR)k0k=7lvkzP+jt8*&@Y(_tTyVhs+ zA4I?MGCTWy@317sjU7z3!M>Z__~a^kvval&#GCL*op3gN7{DvRFvSj@FE$9l+tsZ#d+bBVB1 zgGnqY#~FA)STaYe|ygU0FWbA`be4$)oqZ#KZQpC9=;A8yKRSW;$T zztk2kICFu+!0}I+Pdxb}7hoD=1h|DPyc()!IP`*tBBFZK$BeE}3yZD&_LHxC+qSJ+ z&y1yxiC?#MVL(K>x&Db3BAEfUvzen{c9mWKwl`h~4Vf05PtS1J&+#Cj!(o{&l89+E zg%^%PM7U3e9+8ffg9{oF^mXp1gq2s5?wRx-dwOjr)AlXDxWne9N-T*%jA9xx8FO7> zBurzu>JxfzTECE0pQ}Mtl*C1}gU4!6v)snWt=^yut~;xJJos z6(mcViXd1hhzoU!HH6@Zw*vJ*el5KB0He0{ZadK4Y@7BzY^8`WYVoKz3(uh|=FYQO zaQ4+K*l9K=wIX#g@%o+xKMqS}Mu@ZZGgbC?dhfJ{qG-##^bEA8uZ!n<4)@z0T$wz- zZ?847+bTuA8oay>q0~X{8QP5((-!(!JDC@DHI4pRc%7fK+7Lz={@de`D3Gvv5x>u^X z#h%_L|2Fv;GcLuCT>->3X|v#(YpSZO9IjRFKokPq4`)4gEiuZYHVQ;^_udv}gq?Pn znMDhWfrC)+9v1i#5GpI56UF0$1k?9S!kIcm^^WdSj<<2VC^mSIi5oo{`aX^}=4k-m zOG%I^iSP0ywTt5ckTg`y5wIOInG^0sHWUJc)Nj0AF|z5DU^Ar!=IcJ&^*lf_>^6pR0oyy z^DyKXcAGnpP$1gFiKoui4X*-c^8BYiXHWd#M!SHIhqcMmcz7jlF(hJYM_ ziwtKab*w>yi5OT-f3>$))9E5QwrEb8@Uj!5tGCChmMyR|Kllew)M6Cin;DTKnW6)j zjM0g=CceAp*>%=eQ326l)sn4&8Z3~+k0_epuUC@^=`xOyh!*4q;G#v8#OVz{So*`zfjj2CxE#P~+vbEu5I zpv6A#O<(!4J^8~M?KE*flFiV^#JQ+ri}g_!KI_xjpK%dF%prwae;;l*AE|iSr4xc+ zq;fe|Nf{(>?N32Kll`{#Ew3?KK9`4mCKm@H7HG&ZQI?<`Q4)##(w-0Wq{D=PZd}BvPr|SicmB;PX`hY^;PQG!OdduaDco8K@AkDU0NIxCnI-YdL{9L zJb5}e^JyDqcnagHS}Fgy#|Z{OZmB^{Zt+B{74lI5kf@=zuN!DdCshU;{8bE>=$hQQ z2=&XfOL%*9=dr(6`)W#>U}178u2q(^b4@cKpC9NYWjonJsJ-gpgM+FCE_>j*`* zf66%l1p&vcsN)HM6smaV%QeoZbeO=(S3#KKZT#|o*p}Pxur<|HR?^zRj!Z>>a7kw~ z?nBN&5nZ?Aah!pe5Y2bdv`pKfF2FdBJ@i|oGCCxkEAFn!!UU3-E;-PDjI$QD8+q79BCvw714`x z*R-E75Ko((bBC4Si0W&>Cf9!Klr{ap|wkxK9(`+^+Jfc zc&+Kf@Q{^y`jy%}9D1lu8jj)jdOltdG11gToS5>LZ=ob*T3$ELQcv%+1E2YZ+5RR* z?8y090yeDx*`f?muoPzJu%f@FZZ77(iZO@;&&j(!(hxCHbztmvknn3Kh(4QISoO-$Y;EjKlTFTqJG5pazb}3hp*&A9pxQVM{u>Qnu{CO5otaM z5<21_!W|Ru@MtpUK(v*Hw>N3$$y!&O#~?DkdaPP4tt^QNXg~^KmyQ!XgmQ*+ro4I* zYU58eTIoPIzy8h#?Gu0YH&%?5rJCYO7Sjr?AGvflnj~_Q9R|#vKHNLAxn$NEOWWS? zSMOc}osek%xP>fC$xRsm;Fwr&Bmy$!B~)u>x2Tw7&6!x$+s=Z~rk~wvOJLnfFj`Q~ zs{wXJ^ig~f9d(54&JgYc$COPpr?T7uc#`?)kXv90I9IScWA}ZJS^Lj_&C>FI1|%k< ztlTG17n1B$GhU=gcFFS7>@?&`<$Rl93LkNLqZ0|$DGqfg0 z8=dyb*%5(f!q`vtG-fP zR&Y4#9KG~s(NA2ytS7n*tJCR0C+4`aKlf$`6o&U+^SC`jCmNRQD0ne?{@LGU!#qwt z`}NRkal?enH&ObbJ`n~F{bcmJq3x(RDHb5}H49?^$U}vxuerglzw|s?$!-E^TV%?n ztI$<5PnE{;55ww}eH%ALF9vGFWfvg7>|uwO7XDPZ{m*Q*fBWAbqmL!59Bq;U;-gk= z31s-vht(hgYFc+sCo+4uQD!HVXD{n}$KQWwdD-IHgU7$_nO4bJS?F-tARawmfat_2 z^saE8O5BM{A>xvvfs*Pd4b8Ua3!k^=@3_-yu}zt5!wNes?T)IVHXl)5b*zy@WJI(n ze-PtloGxXj9EEV4r40@C+b@01E?+d?l9yfN?_*jOsaX*ZDXIO=vlqSh{5Y^T>&TJ@*^=A)A)#1&8zaVb|DYD^SKtcU@-YiEo7?4}>t z{mhoi5SQg=F;E&{HLF+iGI!GFc!Vjo26Ti^yX4%yxBtV3PAi#TvsY10gfMDTO=rQF zPQt_pG$?t;GS3896=a?Xr<{~P@6s#S>25UPqN$=fhNqN5r8=2JlHJv6n?C<}d*YVc ztR@eug6w!GWJpwly1bE(HFX#A>sdBYi8@5|Zo&ne^oNoOqI_M#gmCwEd;C+MHQT%$ zY?L5gq=*o=HVz7{5@deO#pl}6nqn;eV3$7C?VPGOJxz{72%TQss}9!y2rsAPth}<1 zkf>T}cx#1sC*wJ)V}PS@NS5c505sX(ZS!!4a`CFAZaekls$F*5aV?gSy7|FLM3d^_ zQ;Svxf7ajnu>H%2{?2ay)(@=^vxh}cOTk1T>Q~~(L0gjPM>kLdjZ~HDE?m|3p1=R# z3W(>%6Zh8M1;mymV3HwRc(#!+`Pp$|MS1v%76Pfb-_#? zQy^#QI7zc-HuEFYk}-U|z--$N+s>|!E)D(Kaix>mgF(z?aJ~)GA3FflR)WQmLZI76 ziub~MPkTWaeCpnd4k~iJE6+IF7K4h6(I;Jy=7ey?nTxpefhb~H0XaO@{2$(EKl=6$ zY}37u+I)1WmsZd91Su7#?69M+!(R2j-qdmJd*87#uPkrhi3XgU z6HxYCqmd9HkAUTzs5&c$6H(679Yk(?KeY%(6MMox{(0-X=YE^V4%%5vF=W$nK!qVF zF1X=k3q<~Ch=+eXEk6;l9GP^qs3KJCZECbygb&T@)>-pEf7+_v|Hozv>uit#At4vV z;-pDHanHc-(cCp>*`o&=?7pWr`u_QTWV{JCDx#q-;s%^@#@}S>Pb%4jlsRceHt3)F zK&h)tsiQQbx0&A<+zeQwzt6-Res!$zhkrl%eWs41zgJg3rr@FpP1~`6tNp7Q$k@n` z$F8U|7c8*z7gSm)C>N`(9#hiCJ2Dc8sE<%BZIcybL>EO|2KRN_P2c>E{pzQ;TV-Cc zEnv5oG$LfeQMNo~c}uXC9&$Gc$$V!Sc5-`x%OJAgw|wXi51#jui&jHCQ7<|1Le2>& z^fS|!jtCD$oqCEYx~Wv%AOYNF-JFHCb+E|&{v?GBsFL8o*D*odr#iP2PkjV-=vs|F zypshYK&;~yWWXdz74YJ23DiBGM%E-3BQ+oXQ%j(n?UtLobTZurBBK^E2a|0V)Xlcp zm#wv*|9Ty}J}S_JLTHbbDXB`S!kSX4H8NyllxBouaKWCZKl3vj0xlYn%oErSbhTK2 zTZ^5$WT{=TYMHB<4H=Ave|!SmXSa9;4@5j+IGCkK*}bb1Iec-x^)~d_FK)fV?)u3s z)^(^A)j8ReV9`udeEN^#`k5bfE2WVSY?7rY$TK5cuwsF|`_KRA>8i!2Uz%5yJL4e7 z3g(;>P{y689n{%8#Am0mdDDp5m=OV&0`O-V!`)!4ow93z5~QOHK9=t*3U=q3lhaS2$77pW5`n2+FT4uyW` zrW@^C9?$>49~t(*fC1YWDY2|WNe*2?t>!^+i!jxfTziQw02s>Y+M}ov%~}d zv^`k^hO8omZL6Awj!rNoJ60JYqC1_HA3lgpXI>LZJH03-q5)^d3bed?mN4yIzHpIU z3-Oc#J|CTs7dqRfLF)tw*;p*x4?)iZ&TFXxp2NDEyKEMABA&l@gMH_l|7Fjw-)L3L za4L!_?C`u+UYOZgjKV=q~X`6G(y1s{Fl7F-+%Ra6=}*p1SEL-hmf< zkIF7N=b+o+oDERw=O%2p+eM21g>d}+ZB4d((E@wX8Oz;dpG%#k6X{ce6BA0IsnuiC zt*nPCH(fZt2ksL&`sY6TS=;c~Q!E}aK+Ice?HFz8fh(OoXD$Oa>VN7>4BBC5QPf|A zkDBES+8=-TL%SAVcK-EwHTfG(Oh^nZRn7@$9;}HvtPo5cSl50QV>+CW4lU~x-TAVJ z(}OgUvvQ3NklE$u+BN_AMLYDpAKKR2er0u7#u;QgS=FpE>qM9>KSyFb<%1|o@ z2vK)aSrh`S!hQ5K^Gnyt+;BBkya@iJHzfA)yAehxXor(P;5Z(auBQ(z2W*^{!@8HY z9<(dYTy1B_P&QR913X>_+ALFV_BFTi^H2ciY_JZ=dK~XMmN?IVYg>xKY|@lt&aU{d5X@$q;l2>FTU0J4kNJ7Fz8G z-e+?bFR}Z-{awpvpLuUr5B_>EYoYz+LIR>|0Y;rAP4u&Ip7+NqM8sR=ic3Jb@-U4C z>9hGD^0r%lWgX3}cJ_z<$nwrO4IMo!6j7%^b$rR8;_vdAIIU!v{_WRZY7b)hXv6lc zcDSh>VvXdo>=*^Apy{f$Ov}}_|5004Eaxg4+b!B9{6%h4z8F} zgV+RgBW}6_ihz0$BI#>hPAH^%&4j)l{!w-*v^*eDR#F>I#ChUB@t#|LZU6IwAK7kP z)YP)N?puddg*XH&S-O?s7@03D!4B<##zUwDrd-zf&OiBsA1u1+^!GwI+roDz%Q@YC zIV*6Q#h{_Zanfl$Ogr}(?coXNm5msgx{D|&j!h=#iPIB&uj zvOYbFt_6>=ImpS^P$^{fRZlR+rm0E%7*f$dqTO6URxA!QC8I77&AiSQTaNti>hmwM zRpr`W!)mn%E3i`eN0vFe?Q&T|wOe#VC5X!*MnMBCZ&MwVhf(&)`_|db-@Vy3J+;9~ z@e#J9W`VUewpxBUI@EEIg-_y30DVA$zhcY)#Rl2-K4=YCkFQxa*KT&vvipE&l9;g5<=N`K2h5WVSztBD_C}$cK&12W4N>1i5=j$gHJU8pi-2k=hbS%kTI|2S z`91sXJ@?`yvB>Hw>)hCPC!(QQr4`s$ARh4}-DwyL{XsY*_roN^jOQhoA8@*`2^OZ_*0s41IKxj{XihgydgRDyBYKY~or$HXcue zpwe`u&~1Y7Rrcju(cxCR=cE5-t6zP+)xYa^scW?*s%E)A8aDkSqoX1y%t{Aee3N_> zT~=RWXV#Y3_SqHo{DB7BN5|;_4qcD{>D%jwi0D{#j!1<-J9+iOimV>uslljF^Y#F%I2(aNwbq;T zOg?^>tCOHMpzT6*fC3SB2t9VI;5d={Ya>SEpxyZGAKEW(y$c*qSY@&*>bD5Qdk_&7 zA|8@(Tn4O@d@o(%F8W1Tb*Xjqw6Vv%+b(9H{@r)~{+G*VRev~d{)wxabSyB>IRW(+ z8d1VwNIz!h8u8)uKG1>*gfJa%+md{q~>R#?4RJ)qnIJvn#K5W6LsP z>wfCtrjU%LWpzTBQogC0TVYG;D(u-^4YqOjKI?96u_EN7Jy?3zR91^^>Cwnb=nwqr z)c65s83m-nAVP|5e|%K+Sc*N{wPhuC_Tt5M!ID~c2nT6#_=z}bJolYDTnWv?!KIJg zdVjnirP-6TGJ7!of!`P_Dn{7|b8>gzc()VJmcwmUSvrdWA}V1djZ+OMI|Y|*S`Caz z{22*-q({7~VZW_9ccuN#+u!u`SueWaHF+g@+x>%6?85WUw1t$ifMiqpjxvZl zb}Sdp2rFtZtc;P4MOR#Gy+ujeerPXKS?wt4u_Cy&Bz6q_TTOeoIQ}$L1=nT(RS50? zA!m|nA^ZRu_wsjM0Y&UMw97U>^jj<1-)I&1-DcGcN-3UGgBxjZtCWN=Iz&i|dA6de z)K)F7vxPX{>q3XG8xE@ z@#3hAUhq%>&gn7>Cd`=P%tR1np{tZ_nJ>bK%XOzMx3lU|9EYJ3*D3B@;*;<>nkZ?I zs9EA<{2X%SlQBYwJ;rNCR+Vq`czP2-3c^pE5KH7-cL^UX3)%i#VCx^)Y@hwu7ws26 zy9-sgJeyrvi?2Ik0UOP>Tp6CT=&7#rFa*t3Hf!r{x3=DP+{&cvP49Y3*Sr4geXpK- z{(_I>739fI-6<7v&VkZ+YQs!$LL;;}_Dy`5M5f{@DwZP!$Rq-zAWlueEn&0zsLqnY z4RK<{5?cnxw(O0sv%x#>vGup#X`44~wsPVW(PfH2sC+oQVDvXsTQ&9INEmL8?d(K- z$S3Jk)8!7YRV%$!eS)Jj=a8vbKAg2=xLwUnwur@zCLHIj|Iv?Z^Ak_mCBOG(D}MP) z#aessPeK%BK~J2e(i3<@NR>YOo2<6B%9hujXOA52upMlVJ$M)ed|=nlv@p_})glW6 zC2^gWb5;l)IJz798-sr6!>qfpz8wyq(3V-B9{EzDIVYkjuS%`5YE@mLCQWZ;yoG6M zdzUS!tGDG#m)MHx0$T-eihHzxgzT8!r8>9-$1gk?{}J)^a>kX2a?mS1I8x0$iBW#^ zT_&YW1hv@6kbdgfaTjNMcvp*k>#P4|58jK1)I_;emE&3io3nlF+LL;matJU9Tb?7; zHsq)5(@fw&^+nfQWv_el>;F&rn$nLm6VqsVN`{;hP)zjq%S^u;kp)@Qh^`9b!&syi z6Jg!>oome27^_!}`N7Z^+Ka0o;^09GBRmqqhma^@ldgJ2DY51kTjHI+XJ@_P^;m^} z)^^?ZuYxzB5ULL0)YsV7@gAz2`rkX`bXQzW%^4+40@MQ znZyyqSG)_?k+y(_Cc&8J_)d}@p8BZx56L$Z$Q(+fRNpbc#t-Z=mLzQ7mJRl+fBd-3 z`Q@E<@gKj>5~r^QAk>w(f`hAYk*3P8cGOY`srh2lHSBciRgp%=3@rI zh9K)zvJLBUY>LvyVo*O;trC>8i1L;*@W@_56^n6ePCt!>luD}yCB$uNx{d=?N*R?? z7%s7AG;LSvaosqns$mcc_!gBej-%*D9ip8IW>Qk7< zzQ&aO;Jw$%5pLpOaFm)xPaRFjMX@l?v8bp&@WyD|?|)0x{4NAagNsE$!9DP0Gt z^5jt&`_(;g-`8Sx|Gf{{jo-P^_Uzh=oU_X6s^&R&%`zzqUl}sdhkUe`jR8q91uPu( zqm8oXz#cn&%^CKZH@)NFwXeMN6^x|oz^zcrD4$dGHv^g6RZwGII;ay%fm>(!Nb(@i zb9m>7J52h6X}dU9G^V3@xmiAthB38r<0NJ9A@Yv7btEy+IfRLB2i?>gY4sVrONRW z3>%%X)u@KCN2}))l7Sp5XrbOa&_ccTs;N*|sh2|o0v$-yu&wn{qDp@Om&m&D z%L@gU!|6h5W4DxoyYhuV=nxwr-ndxlJK;J>>D^bPOE)|KTmbJQW$=mX7)hK_)HU!{ zji?4RbrW)q3XB2NOx%Q2eg~1|Jp?1-&JdW?LGQ;jYc}Wk!~98IJvNRfa)%! zh^7m#75CdfOQ?#5=UPK3@;?eGF zbN~hBXl6`!*4iV%W5IXz;-mHc*W{r6;PBwEINUi0z3@2gq%EI{w(YN<8hAA!04TiB zM0#w&Vu9g0xzl!o&xH{kTsQV*BdY9XDc!sU8e4~C??{)Tyke;=ECK*)ZjuBAtscnP zFlhN|s7Z!2!+<{E9rL5D4xoBhX`9K93vHx)iU!^UVJH0l!$Kn@A}&Uv01DkZwG&A~ z3Xrbt0sI|s5+;BsNHuvAxUwn`CCBY2ye=cw?^Aorv<)UI+Wduv`1FuvRs2K%%{kY! zW~5ia>+tO{W2u*b5v-tSm`S2gW`)y3l@C|UIU!kes%B= z|1|qz?Vz8>#}77)%YAHF$f4tV>sCqNz(OSf%kr3@V0>U2jKgqFRKUrz{VRR7CEZC^ zB?Dw9{iW7deODuG`IfM7%TMi=7^D)wXhq(k%zZ`j*^IAb@%*1)vucz0h*aPt)>N3m z%@9pgRXH$zsxZDmUsS z86YtjCh6_4ByQ7A!iEh)N08%%Zy!KI_U{uX4Aist?Ujn+QYp#Hh0A4;Fwlt`X_lRk zBYGVUaCT5kVMHIQ6&9pVupqj*IoyurH?-*RsFQ-r7$iR|b2~gQ#9Hz)Zdkz3K0NNkXnpG;?<3#{Ywwa<-74s7N zBCvyjN@y097!fRPeiGx9bA4ty(fod{@du zv{&^RTXu>4!0itxd@__59xzHd$>H4NTl7)qzYE6|+o1*}6h9QzfY>&pO+No{uDti| z2jYQdJdV62*sQS&Y6g9{auA*WG?-W_E0*wO2I z4DHB#?CHnaFL3L|Wy=b?ZQ8Q)`t%)HqpcQm)QC~%{ikQopr=qTM`5!s+Nf#7W&$|t zjyc?2d-$3$y?-EZgr1;9y=2vG$1e;__2yN-MCcqjAF8#<&Lk(OPY`~mGLJijRlJ6j z!je+pi_cv3U<+_QcB+?yH}KP{x?b!eAR^~Ggj_%XfFX>z6;LAmu|hN6leA_1JWeeD zUo`IHhlRKH*Qvmc-~GRNM;tz~qOQReTq3Kwd1cMj1SQtbI?3g6t2co+^ie(<79wtB zSgY_xs35&m#<5zGM*r}dn(Ocb#ot^7guEkvbIaaxi>aczB^;6-iZVcVt}4vnq~S(T zeLhb07q*Z^-|97Md@bMy$N1rK{{-V-Az(-26pkGfa_(#cebH$V;3zlB(w|q#7ax5o zTQ_WzsIVB-Pm>42BLXP6d|tug;uu6R!7PdC#yuVgS+KQ7+T_}C*Oi|?{G5@HbAAVq zt4nru-5>p%IMHW}PhD{FWg{N`I6u!F=5ayF?Bu;X^7GF>J^I=kPv@bISN^D;=5V~x z0Ti9a)6oZ@Hqd@Y2tF3Rbn1!fk5#{hgSL5=gSJd>KANoefE_d9C5840JJDGW9s~PK z86ph^S-@$jw;ve_C7S2pH{S%FNAP9Qx3%t}XhyDste)aNaDlo9u4N&&Nz){9pXxe& z%Y&>}lM(Wp>W>0gec?;)s`kxzjlZy6EOidk57Tu~ji`0G;*I_!x@dXUt@J;}H!(8d(uH+WCq>X0e#d?+gs10e{{GcmdY z01G`s8w?&&K&Lb=^|y4|Sm zetGfkul98^!H3>%gYp$))yw>2-YVI(d#@~8w&pxk9stmTQkcogS=5VFYpV}91)SO- zRr8xRB5`8PL+0ftTG4uRV5=3gz%kDu%&E-(4k%IpVEG;pH25BHS;!Y!fA4rIKl&@J zzTzL@k4tS`%g-y!Cd}?O?QC@(E7D7?7e?E~tM$6MhbQn_wvu335*aYA+QE&wRGM;3C5RIagD4gfB-Oa0U9tJ!nlH_EFSMV(R5tCg2H zP-O7dZpEv z_`*j+?t9>G^TX^(5S_G($MZ*&e6&yAR% zWT1SAl!cNLP&2m9t*A%J5x{=(U+vdHAC$HC@x10z&>>Y+u&*evN6wYL02w2?BYV@k`Ri~Z$s_*A{wM*UKwT~U}U9W&U z{TBfsJ(vkhoJ<(SgMnZXtiyw#a9__^Ez{rsL_CO|<#C%~K@f|OdN>zN_5I_^5yJMXy_z|K&gGy6Rj|J$C+}KE2;ZB#W%38g5p%Uj10z{`lLaALdVf zuY0-wwEAu8R0_PL<%W7a2%f;uRZFtuowq-bty|I%v>1Nt;E)YqS(LN~9JiVx&_3$S z+*qP>A~IriQspg|g0g&xj*65!@4vn3l3~5Ckr zuhCcm-#tW{pXQyYa?RqtLluu>Itg$Ie+~9P^eU=_F5Gkf{p-9GQ``~ z70ZJ8OXRc9XTns?E0K}W%Jhx0URrxF3#Rh=s;-9Ir(10BJS(p%!YOXK;l`_E)Tqm! zi}c9f5u+0t%la3r08E#TdTwzQGs40E#fEg@W@rx+l58@1%n-Ti>T~ap4v|lAr(6K% z388tfO_jz6P_G-odcbD^K()cbp`;BbF6Xs!=wYOv5!ePOa4JyXpezI56aTxC53}MK z(`U-Uc|XH;)+r(O7)ef!lw!yiU2wtF=1;6Cl-U_;gBna({yVXS3nrHDUAniG@#DvS z)1^nt@rG~%HQ)_a7B0!?xo3AqWI{qqxP-zb77i9Zc;!9wNt=dM@ydLPKN`V_xrB;f$sMQj(m>; zrfihuT98V`;s|W{X`d)r$%s1cm0&2RBQ~e5^2QlUNtDUrlepMe zv_bxoSLRF4&XkMa{NM6(e)@5R?Ag5sGT2I~bimpdZMVQN!(w*HMMKWsURdbs9~ITS zB04oXfWqJzOL)vewU$<#B{>cc4v+d?eS72&FK}jn0?m~I9L?Igt7hEmziYQyAN2}M zlu@q8FF$9K7|K2s+`80Q2E;Wz}X6H^URDK*A&Ja?9AU zRhL|P{xy-QrUsF7)^2m{?}$tv;c`3B1}Lha^@qhRK-4RbJo3Dpc6yInH*DA>8JYQr ztqa#t^u-bshDjn^tl^MLpuq77VI<1r%P$voKpoqG8!bSK1`#jRZs)OnZ*%}f{7)An zR=zC_ORgPr<>M(G z!~Ti)?YM`T>(DlNX;?T6<&o|cnU3KF1}+((o|#!LUwpmIqkvl#%CK=0nhFFA^ z03+*A*9?&;62%JK?j}BGeeAH|r#*p#PuBFcX}{H`dZV-iT0e@tRpHWInJ{6C z(7sAuqswgca{}7{1x`u|)B;kXqZffpjPxR_fmIb5ifk&f1IstFzkxCQ7gAA(C{T#c zX@!rv;_Bc4K+rLe+f*zp{t<1V$R<#gl@-H-t3n2y)nCS3H|o>gXSBQ>z*#SQ&ZBuA z{rjdYNKTA#Wn~yFZUmh6fcxa16@f}ZA+I&UeVEa=Fjt_sRC*i(yzNxHQ7DzEkN2T( zCSx$bH&Uj)`}q^;KHuNl7z}{brZ0^Spz6ui>bLS)2IoopH2&2dK($V*^|gB5uC*`l zwc#kx+~`X*s9oy*u6?W-em_)m384J=k2@h7w3)FSM^R2_coit+`fmPidH0`hr7v@Jl}b!pnA~#PotuYV*k^#RTwgRAlQ=|0?!4pe%YSs<-5rWh!F079W3-iPt3Qp8eE_T>j4jVSI{N@{njsh+( z1d#EKYLYVa{Ny=B58d|Jq?iADl~Q=2&lKBwpb4vjSRn{OYm$=_CADQIId4dRX@{s_ zA;F>YzyHmZ?-u-`ax9Tp2KekV`=`qxr=cUKCV;~A4O)23{}>Nd$vr8n;UHqTB zN`0Uh44Zm)7|ff&Kd7iN2RV@;Ghg}*>@GL`X~KhDyGOr)cdTAU>FMb{+b=&ayP~wj zF>&zV{vUVh7Wy>mR15AS?JL0><(e*?pC0%5r?YO!$thFW^7r;a)vE-1q&0pS0WfnX3?_p0Qdb?MUx^yw7WN4pdB@-#t(o z_|glhy72j^XH*wB>;A63BJd?Zf#y#E@(0yRdV(jtfskGr5wnU*M85p&XPNrWY;huG zwh?Ky8N{Q4$qIoOT(;AFh%q@CkV|=sp+0h>g@w5QPq!qcgvvb+-1G67=eDPu6Oz+o zFB>=df{IFVZ-4x;f4s4EOFGPoyfD(A`^4jqk6nXWzc|{O{h&J)*YR`MQd;HfzIKb} zwi)lw05?vEA|8Nn(0Qe{it!>B<-)^O(1-^c9Y6t)l^}8iLu9X5w-kOXa zaf2LYP;fA0g)V5~T?$YMob(VE7W59Ci(m8lYSWc%{NP= zq!^QjEfiXM#Am>AKRaiyjGu7J?ItPfON8agrbjiER{jsf~NBr|K2( zciIGQjM{gns{-;+j{=s_qlP#}kG|xJq}DQ@OJ)D5$F!;N`BLAXvF7V3Q$FiaTm(5P zwEa}(R8@iN1=|;nXii?QVb?KLevpec`g}nvXMBHeet!AA4?Z>}wIJ6azpdR36D>Fa z0Gh(XBN1Q($?9OcnxDU4MqY8=JLe5xBAHfGSnENQH$}hk=_MLe$YtFY)Uh0&@#Ewc6O_L*w1=2qh zJ?knxj5z+uY>?y3Ey#w)ky|dj_)HmpO++vos_IZ^?r z0!_}v&>lhm2sq{N(mw}lYG7Z00?nTS%-q7%A+-xfH4E9p&pzEG)27YBa(EAn#}gsv zqyh*wolXY;g!YgwY_UF9g$x9i@kCw4SX4=$ejR1PgsWzrdts}a0VaUr`jy;VU#DlD zo4=N$(z%t~cmKVM&N(x(-l6T-;+^}PU01JK z-z6cwHM$moK87hqN{nRyZvz6NREooq3y!@CVfBVT_u&0Qsl2Kehh0BP9sKIX2T;h( zF_)?V!L4S}1TGT;gg&}zps2xe@CFC=1}MMJEwFrQr-ieaZ94u!oa^p=` zrjNO4&}CLb{o`{|<~Vuk%EvDq`OvfCWkQuuC03|{MF4{;2L;3J68c^Od;fu*8?sj@?q{K~Kd&IAV!9fO(H_)w) zYc-7ypa4oN;W?@J2Ttwo)qirWU0dLLfC3Fn0lw4B82}@AwIU+e_*pmqoj8PNeYHWR zygO5N?I=+G+tHCpQsFE?@Q)AxqZ=A@f|d@v{+OMr8V{DtrIOSlMxMIkk#7eLO&uF% zFyu63C)RD*xpd#&{IKNYwpcQkLC&dh!(JE>Da92<2|naXG6X3wjS7!KdXTv?`s!{Y z(T?vMvMm5f&Lb=QpN6cu(due+0L7D0W=x!4YUUVyKGyqY_f-H< zj|ZG6#<>N?@s#_4NtK&!9hq^f|?*sFv!;RX)=A6D6 zeUqb3EfsXFV_mXvmL{0e^)rB}b*U5heLN|k&)_2{TYSMbP?Vg0>- zy5oj%?c2+Te$MQ;bgq4?#HX$pdBMo9X3gth4zfwB)~)2P4?mUOufP3=J^N(LGf%%} z-T2#HNZP;+!{SpGU$wf_o7k%I4%u4K`U)^0QEoys?$ozKmD92HGfFk zf`O(V{ry%S%D+Dn*b|_@A5oz0Dn~z`lXTs}L8zb4?5*C2!b%98&5y2+SpN4`1a z!j2CEIC0VOEp6b%15UEbRacxnps2{vu}6>2D-#oC6S-ZKJDz*y{-w9v_}4yF6&~U8 zy$q4-O;#H?ZLhpHb=FIW3jbDfiwb{yDR%hU8y!Gtr9t_y`Y?j*!E|hD{4#e7W^RsO zjAb>9D^>GmlgGxbPvM>aPH6 z2$TQ?j*S8wMam+%`f@I%Il35DjuFEuT;&+5J_)wL{Ssb424ARb_%#dBlD?Fmep-$= zm7$2w8H1%dJZRvigE);^Xa{hf%3~R0l{|tI$<$o1sVptemawRDx%rNv1viYjZg_mW zd1-S4BDBX*P~bar@wcnjZ`_c92_P6UUMrMauoMkVlz+T1`La$^p6U%kF{sEXUm6`i zp?GsKh%&t{2%gokMf{J#=fn!1hIB|K#c0*a4)m0NOaTJap916}HPAd%T{J`jp9sLv zEJQru9<2aRmYj@Cm?V89b7n5b$~;)*@3A6(j~CV?jK%50m{sE$d&rz|zGw7x8(k}BssCY zlq0YP)2&w^JulO?8JW08fGPC)Y zL1)K3bm`@1-SXvED}s%TTMA9R1uj+b2}u-PBn~{I#}M>lZu9TS@oizF1E|4m(#)82 z4ip0rx<~*f5@2EEc`!KD5*}V1)ujewac-alC{Pay)E+=OQ|bpiPU_xDxKV~#1s;a7 za>Xur>)-FGbQ;JkERpt>;;djw?jS7L84Mh$5HV)Shyg}1hFLk&@zPix1x)7SkKeQL z!lB(pL`E8R)T7mnekp*yDkI-F>c^!U=jG?)orJXv7lvNAsyZA#nKF6$bWAw0IPa8Z zZ5kawTO=hrw?LlcqXC>MocS@uX_h|6tbW*e|xMAGL^-n+fT93r!)`%Qcfxg+{dTNk`3zkMN zUw%ajsJ9QFQ?}r-H*T?p+gy0qYPrOyHB2bQS)9cTiMz|efd2lmz(MXuOpbLH!lSlJ z-=lU1{sky-3F-|@33$cd;!7#p3^78k|fPsDBetGlbU3)iN+Ti{BeW~wGnep_s*W7(`Sus+0 zxJ_zF?KLAa@&gH*sfjwxVcsbbsKwXFt zx?;s|?Lff*fPx5(SE6HGMyk>=_$)|O;KrXG%8m)Oip$GHs$dRBArrG}1xkPd$3OvX zOx0Y-iC4|Mejjf&73&}hQ22J<26^w@=>Sm&wCiCoIpRTp1y-m&O!5>nF=7&pMD%No zP;^?6F)}wVQ#yC+ELU80^PG`GyN^fq%X){I<6W|{d~IgV{OO(X6COJ+I}_pMkme&Q zJQXrlD7wseZ;Vc1q^21kEQ-y}bf#q%`r0H#8Fum7hAP1ZL;CkWW&AH~`>VHGVRhic zL_@dz(2zLk)un%fx|udqn;Wy9M(02!BHHD}GRcFe3uZ)taZ_Hz00!8aFu2{N5I#BJ zEmpn6uOSCt0zX4qvor85K!G|GIB;!()s9+l>uMdG%<;yP@L9hiOFjYDxnlV`qzw)i zC**q;V5bjmmMoNQa>b;XENeA$!Q?e^&5w`KBY%DLuH8c~>wS4>v|+uvsGk2ITa5a8 z-p6?O5G^sPABA;$ZE-DI7;rW5}ESWhw{tP4H#eW{SFGns>my$j3oz6I&+p|cq+SN z6Wke%W~)@f4by;CQ3cleZ8|<2J>s4bDTgqn*0a^e*%U83$iN9>*z@F&dTGh!0 z`iH(%<`nySpEbDs_N`mDN#8zw|I(v#>}%Msle&TKbmCRh_yB6NxhzrPB6(QlV3|%+ zCMEF%Fp>i`Gdjb*3=HP(7%cGU&>xY1>lc@vc$5yb__$I)8y+nEdyz}8aE@i zj}w_CEiQw6J@XqZdq0ORJn>^ z9&Hed%_M~oH5g#v4%;H!9`6Yz2E0A;%~$iTz>Wq5Q1&lA!jP7po*q1K%n%>?+#sR# zSnr8m8XrI_E8XF-apFwd1I;JpoHZom0H!%zM%s2sc3r?>fq`9foa=Wopf#^atz&_& zrxXP=fYiFIaibg+HQXn`giCQXez4LG#oDlaXNurQHp$6hW&E*dQ1VJ4X}WubiWh3n>GzHSsYmFiT$eTC{LmqQb;UFC;FmFw-lmIsQa3 zW6aO6)YoM<{pVO?G`XP}UAqQ7Q7E=>yNnnSL6&gH5^(2-*4)TxC$@x-0mJ9oE@4iVXi2D|Th^uq8h+qM;L*t}Qo ztr9tyjONZb9w?1OfyM_=Jp3MK_LHwapDoFu;h145j3*DF_)W1Rz-#`#{em?LESDoR zO?&`28)-P4ptpgR-04QXbjFrrf!#N~F-!Kj7OoyrKk?e5nk+Xn;)k)0jJ2cZ!${;KX2U_+m0ymIPVs_i;H^ z>401l_os)R2l5Adh*cha;?Jv3>n;Op-yibQ%9gE?W&P%zXb}4it{DwS4tZc~pfnZ* z8XZ76d;5O)ac@LaRH_#NTq$$n(w%`A_&vfJEW2_cA1%Nq6?VG1C6j+Ok5d9AK!F1& zK(n}Da}aEZVHyVyHXkH(Urk>qpH2T<^7iCQGSc*#5b&d_ipmx%fD(&+j5j0B<+WAt zexugi2l*mXc9lb6)ARJsa`o8DruVz3<#BhvJgrBU1u4lf5GOd%E{<@#mb6O2m`_ZM zlQu17OdaqvrDw@|8#ZhJ*9rNk{~h7?GtL+!Ge1I4j)P(S0Yne{P!#YBeHxh>DM@d| zB`0GUMb1+LP$t&mtZTPe#aZr2d%# zJ-FN@`DObhEZ!{-Ja)t8f4q5ThyFua-2fnhUET35-MYn>T{U{hJ5`=c064@7)Jp-# zp>LOcP^hlo zJiaXs)UH#YNubGBSk`OD{g13I{AHztaI(b<hSkfxX#Xj^L8T^mu(M}u$ zXFyI=y;lnIHQ?1dQG2Ti0&4FGd_SQmz=y0CH98@U#8TF$I5QsL6ZTK6%6tR6FoyQ5 zN|(<*{z_IY+lnaa08F3=L($PWBN*mOZbXo$+>V?Jb}&yc9SrX!vTGCXd?$p zbFgS`_^dO~mkH)^L7^5YDlZZ@0vz`p&{M7%clE@MeOtZ&;DjM^)0AJ=7QA`qZIkXc zn_^&dTBbmhVM=@edIJph$%$8Bbru;J1M8(ADW|*?eWe(JZqOcgIcQZVL(V^2CXBuA zmY&_^-Nv2>nuc;sch^RjfwHTH)KrIW!ICxZ@X$UkB-^oY;9r)NcK5`ZVB6WBXkXY^D0ARt-A7(F-88C*=+>;|= z)+mVyjRJ^ZlEo=h1d+p}e4UG1@{<+-XE1_-RC>X6B2HcF4z1+YdvBWG`K)$h0W?TN z+_a@nuc$}PJ*WTOb7n7<*o1fhJiLzZr_n@Xh(p0#7)>@Pj7(Y(XHG8Qv|*eH&u1I7 z`0=uE{wi7W?aImLo!zG|INQ4eAbR|sYm)$|>Q1K)F9fBgeB#-afx)c}4hC8FLD9*C z3Kl2?R)6=MoH6Ak{iWgd8*7(T2>}u0FbS} zY?LYgeOETG-Xh^a5z;BSy;PJ|3Kz0f2x6>7hKJOYaV!C%YTPJL^#V9^#2#grd+xY3 z>)fl(876jF+gtz!?I{0kP1V@t%U4c!Gxagk3*((ILPqOjuqBEdVBS|&UW_0o7FZnw zBS9U(6w7_Ynq$CYca>LSA_2a6+49ZTKi)ZDV8>5EfW`O(%5k7T(*dZ-^L;!5Fq9w} zmlrZFEU*yW21_gq1};zHEYQa9*a=Pp1Bu2X@cmUW!xRw$AbK3eLNlqd=Go$jYqp&D zVs;`MW}#bNf9Vxjy>x|?A^mQ0WFn+Hb}26^17`{A9dKey+{TC(NM4AG@xg@5C9s!U z0P65-E|p71T{a=ITjX>AmbUb1COu~}dh`zZaO9QeJw0{mw;jx;aP$LA1^S_cS9ni? zz(+)ehf4dlZKXrUj>thj2e=A=1>5cO21|HIjLKmY6P*C9ewpk_-~R}zUCg=zrQs>i zWB_Vt(IVgV?ZWK~=l|3p0t{#fBHMT|>$WmHF-EC`0+C_c=GxbjpK zo&C%6v%Xq*T2@wu#6(5Oqqp59ty;xAcp~)qL~Ub}0;t5q%0f9CsPb0yfsQWfaMy6=X&8w7${9kfx1)L@1Mz` z&mee0!-JXCDBFJgO+I|*1KF`*rvxJoW@>n{loXVT6_JU2DsToQJ6Nh{Iwf3#MG2Kh z76jnPF36FHq)55!s$o?_uej)HQ>@HsC^=_(y3bbOlzwSxJI=|?%{{-uQDL)LZ6&Fx zEtj?J++uFW7D}dCZ%zK$gOZ*;_rhK`{P@GxR11TKDBD%6%z~mMV^^+Z?(&SmlO}*d z$)wO$wlfxVTc^536Uboi%%SS#f~` zlkvbCVdTOK1IFN~5^GtdtU&af{)114&|F)MZ~;%)RFUlc`1$)6^<;fyCw{+bAk=Sk z#vP2(i*4Dy0%ex;(}KmYB{xW1XpGol?^sq;q2hHCBwajF$v6p`P#P&^5$9E}1YMkz z5;L(!uNLy->b=jL)wjiq052L_9aF)z?)7Q;gMM4{+#W|M(k%Nh_VG?w5CpUkX>X>z z^U>V^%ZG6uQaIEU|2@;Oho3+>&J^&&&vCxXVXF5Pl=WD0%b$L;ZP_BR?kYigZNR5b zsv!UJV&=63N62=hOBnL}!(zGMe6Xg#eE2UDLCLTv(Gcoa0IDPFVeS_=bbKgK1B!Si zxP?BjYMzUB2JIU8;WTN%2YL||mss+vWZ@TcW#)&UiN%Af02W5LUm7R}RS&slt~Vis z8@+BSVE5=ntU4ETK^2|~>DH&a+v>`_B2#ae_2y7?DaP%f4%&d4FJq2 zh#2f*wW3{IG5HlZO!q;NLV0-w#8E~WKkiD$*zx^)B-AsR-2c5b|N4Kw_Sy6ZduKQT zKr0VFRfDk%wyXv6_S6?n>)JKs*M{n6pq`_rK+UK;`fD5JiZ?&H(!5~>&zi%UL|2N8(bJMyxs-vHGKK?w!hu^rzajODt1d^Qdbz_BVY%D zGgl&|F^lHeL{%mxe1N{q7NWSs$&+UW@7c90t-#@H6&-x+V1DPVLuUNAX#M$XR%G6k z9M=K4h`^09`C?JAgj(#75(i3CQlQBJ)G!eacl-C>8ZzyJud>s3NL;X0vsS`V-V3u7 zSVjXt5o7tsU#0hXzlmHjSVgL5yhmmSRO}8Z$d|M>>(i7}Jq7RW$2ryW+T5saC&Yb5 z$gAmcs7g_l6z|TIsc%k}&8s$w4^qRH2>QXC?BqDf&2e(nR_eGK-|6;E?Q%&`o;V;Q zHzGdg_&<%4vo0PyHLPtogMMhUuXcxe|DQc~+oKbonDm(05{;A^ky26uTT3*`0wq-t z+QP7NEbJA*lf?uVQ8QwX#ze=-GH|T_el>UvfH)CtL&uK3a5DJhlTU8ju_e1*r7QCs zdS#UqX2@kD&R&+wqL&ec$O^q{2K{FqB4sQ(c)nMPA@dI@&I_!^^&m>03g+*;jwZ=g{Ks!-#KT< zi0ejGMYfAO(-3KB@MY|(Rk?ldy!Xk~l@2?6&ZDq&4^!ang{Z)Ygl<7W0C2chG9ZZ; zA_uR}u7DIx#-tBr7X0x|m=#J&_sYxveE2UzhqQjBx+BN%W#Ys|=B*o6{mbX^T{!sc ze*e7Vfpd>rc)eq2-YI)Y&FE}m68N_4ym{qgPfqr3-X;-{CwZ8B8^y{O2_6|-I^_X` zDSOr+@<`H04i^9bDP>7SK~%qoZkM2;gW(?!U`6&sB_E>#LNENJ-?L`)47` z3Hm!qVB8*sJVVq+!v`J4nn2D<`F_f$aKT(4B{@YB1G6MImhp5;L}qndib}BZ@WBR@ zz)2r(6C!d|0;Culv$V28dJX6+qprWEpyi;p4@;?hcsy)6F`=6ueCX|>h2O0SF&d+h zizpKDMgf-Y3Q0-|lN)ZhRL(rBBO*PS5I58%+qdqO&p-P?e*AGQB0_~gu8ZZo8~K;e zC#NG{x^#;3e){<%wqxZ&N!CDVo)l>EC44nmJZ;|ZaQ=D!S-(5O!fk&*!K7glU7`ciF!E@2q z?+B8e{{3=!|E+f<^S7N69~LVuV^YLXRs}H(;&)=gGy^O-_qn_-abuZEMUf@MA|;Lr zDX1ut_>^S1ZNjZN11~@88hBVN0T}6wZG&{Pb|uS}?YMmYyhS1QkW>J;UF9Hh!!JEP z-U4p&!HwX9~weJ)7e&SQ0*#M}ao5AVZy8GtnAAXtUSho?T!h$ z40hgHA=k;JECL%lx9pbLAATxJ7cN#ok6XqitDqOf6>P4P)tSmy2 zX%fat1(hY@K_sp#uNzl&<+!WIO0;|l(9&Vqf3t?)EL`}*>xdAq4Ew8`!=Db zR43d?vaQCLX3?LHEoZbndr(#dW^E@FNJd75fSHK$0|r7`A+&E75+Q46&6UcZR*0n( zCUA_>!?cU~%Z;u6-YYPu4FJuelg+acq!m9p?NlodM?3vQZuJYfC3tdF?J1IPCjC#I zx#vMyy>N+yIN@35LL{W(as`-fq~S0^m9G5M^&IP{$PF`{^o(>Vhlx_pfqi7s+pj%& z<^5NO8)6Jh9emuu6C7p4wryFd9xlVd9S0*LXN99gPCLD$^y{BUMO8I;qL&90tHH4G z)(O|W3IPU|@lIR^x6(?73h2CM&8DjkI63g+q@aM#Gc=3N@CET@1y`N6R$ZGDCKgelv2OkqSPCly5$QJqO|$ln>j~iTr0n5TbX#fgnbC#-z8t^(;s@F(w0W!BX9Wy^{+k`xgw zDKO>nR5}&MN${kxIp;yI8!96{B50{A5#hMB0M9^rh*vhK7Q9BiCk#Lgtbm7W&^*7a}S+Nf*qLzMlS>Y+1EV zoE2q~7#;=rA577JMkcsAdJvM(f(mHY$w$dJoxCUOEN1r0V51BgdXZdr^SB#=T87WS z7|@%6Ga9!*AXLG8MAZeNB%9SP`}gHaaj~3%{p+fa9pnpa?BlB{VOao0k`d`cOlC%R zsFH}tSVw^SJP5%~@LkOgKuJ$SXlS-?^UlY2ZQT5KM|P1|@zznMWPwQwV~19jmLb$x zkVIi{um0c*NotWI<`Ea+?Q~$k;uVKkjM7gWlx5-#PVlF8oSILv5ZG8qy1IqO6zK?W zL_&PN``>g~Id73v?Jtm|=vXO)J*NrwoMn(*JK(KDQzV9RC6lVAHdNvQfYJ@O3gFUx zP+u8-!{})#gSy=XfGOiyO<52WEMJTSPz}R92(f5KQo7&PZI^v}%AUa_{?_3DJ~LDP zx_eg+KsQv$P{WX#hJN!cT6O-mDf<<;_wk{C{=OWa+Ury6`c*Go_}6>4?!`-3jD%n= zyoesWb>w9DF+iadh2-BIpqNS@zLvG3QlCG}1{_As(d_9yvb9{LDaLf~TTC zTn~-Nm|1}gm{l-SD#Ju)X%Q_qJ^ttIcf9^g#};RGAKx6nlie;zl#K2@+rpbjrwAq! zj46X5O#b=GzvGK4Wqcj-RR64W`7U~Y`uyt)3M&!#CIaKn2k#{W8nGLt|A1aIs!t4j zIcX?RGfJ9Smkgsvd!$#_b59>NLW+YeV#e~EawKM2q|%+AAOK`MYz*yr#q!-hUx&YE zHn<{yCSG<6^2;+oGi7)DP@zw=8S)ji*N1g~H#0IcYIF3#P#Z+4Aa|Eks(kBI5@jKs z#%p){Ro?mAB$515Xx5=B!8yD}zm7|FidmQ}kkNyfo`UJmkhn-}2@x{trt4gf|NGTZ z9fl6*j2NBU8?}>vaIh#?{?foSSKKtYw1)c_E17*4mi^VA65q9ZwcCQ70aO=R~6OaP>m~XaC z_wCLb|MLTXnQGgzT~e_;_rmkT0EGnJQG_wWi;6*7i~uAV?o#m~>iBv8{VbP$K`*j%6_MbHWYdU(^F6omCPbaO^Ql0t_1TGaj)52%M!YD~x1dx)PxSUwZ!{Sp)Top3tlJn*A3D>+F z9Ny|FLz`m{^~T!k7JyjHuj|q#+QV#lo!hqf8#r2uSdXcs=lBvIyyMl(P3todxHtmF z^q2%-i)=8u(4R6%X%QVm7;X?AQ@Icg}p-^c%eB?8)$4iVz35aQH4k ziL_rHd}P806Rzzx_Lv$IxTslEp!owR*H1sJ{9)-66VHxA;xL;7+>la@5)=WX$g;?I zkTiHMiVBmWUOnZar=AdrkHA{rg5_5Y=Sj{8I*$Vifr3gWzWzLP(gP@aUzY|HbAUTn z5J-aPA8?jTAG{hN=H|Tru~;y9MIyu?HPWS(kZ&SEkB83!nN{^F6@cP0YTP-&l_1w} zYL^aj?d{`#jvCnWYD0)26NekD05}aRSMI<1`4=aBoRgCy<&~v!^_Y=!+<(4t#Kd|i zqrUun$D%NQ(yL`JUYu>A`how48B@V4E zfnT-N20=Zv6J&l2FsOGxZnY0E5Z1Ss40!G_krbpvM(8`ZTWj7fL@`08s&QP< z?)yPhJE))pM^B!h>ed{6#YT&HpOdCq*V^m4aH6 zYa$hqqCKx=P9h5k=|Jc~dt@jSNKVNqDUq1AsWRf`v3aSzyIyW-9lab}q23DBl!o}X zZ=dh#Ye)a(lfpuW*h9mi;ddh)aEAQr|DJqu=s8{gcC7aRI2vDk@$1=dPyTFJd~7@T z!JFZp8lv2Xz2HVE-=uvfT~LEKiMy&0KqOeo3z4%ZBv{HE8BlK8yl=erRJ$%+47-lC z9f9kbHwBud7QQaY49UqAzD!5Y3moO?KfLj>M1~^fB3@XgeDxp$BNzi^A`=XGToSbO z`;kw6!TpcOke8kXh$cbl1kQm=dB{>#@q-8fL=y&RFk1J%C-ZOiT`vYky5fSJFh?o4dOj&x@V{+!iN5#;qi5wxn8zRHUjQ*FkSDW9Zn@~4w;D2q}q zyg5_8`11Q70fMmr!&-)&N8SJeKS8v8r`8X={muuIGBR_;QyvDz7~DG`k2gWVln|Ss zfU^`vqCQWVBp?^l!?#{PfB5BnuS{&l**}k*3V|~ZM*;nHI@~$U>X>iu{(F9#`1~9B zi+_~P(J|sEFII{SBg|(s*%OyqVJgLIiPbDSgAFqB;RnQg>G@cLqPrH%8CA2AV$bJL&2@P5ZIVG)&U}#DUzQo z%2gJ!KT?O54W(GF=Q&EHL;pT<@t9HHwHbQ$4Y;O3<(#HoFc>B^8N=e{;x}`usksdo z|DCk5hl;Zd`LHcEyzFMR+ysN9UhYcRA36}QVjto-_8d7>THiKKBsmIZHBQZ@6hL8w zhE?gCl^~U5AW2RR@MLcsu#IIv4A4!1p&J~fnSG`<4O$+@lGU4vAcVX7;-sSzzt0S9GlX7Z{2nG zlecDPqp$WD#P0N|xzb=Pku%O{A(b=wDIdzdpVmmE2QG&INagK~wK^qWH3YqWk%9D$&|l8_rUI97j$lWJlfcx9S&4>!cpLag$f0t z>1l85oAmbGyTFMi0~-v8d~Sug2@7R*)DS!I()(a;!=-yJOm7OX9e)2^A|o#Wh%y*6 zxG21CNEnO%)S?`UBsx9-Sya(~`+w>izdht3tI^MEiY+Z8cjU+~?|&vMzFr{SqH;+H ziv&lG1F&E)fll-^BHdh=Pq;)Ucv4|!!^BjH`DHsmsnvjb2f=STPNdNn|aVTT&L zy#D6G=iib5NY39X;!&FrNKS^ z`9Fv1*dc)PP^Z^-Kl*Xlg8reqT681*MEx3W^-q~o(iiQXHXvF6YUSmP3?!+rtk@>Nx}NkSOc__zd)0Hsp5EqO|UR zzVDSsZMIagBIW^udwe}-x%BOG+P%2Xa|gLs{PGnWk*Ts=qQg0)`3zai5{~HihzKvA zfBgM>7%z+|dd#`nwK@a;0~DyCzzGYW?1CRepJ?&uU-npAwEge8&%Th>>=BHqixCwl zIzA4$w3%&(=1$NbV<{U7Q>GxGL;25ZWXZ;K>2c{r5;gu>crPKp5)s$u!g3ea0Bn&w z7rU6*hDPRmDYZCH+_I?GlpLoHQUDvc<=~?Z`~T@LbM1Y<|E|?ovtO$lzjcVxw+GaX zLY z>;TXd-yzt*wgQM+h*+!PEfSP=y~ps25!KrGnjzZuU;SRkW1F77H&MmoM7kDo!<4Fo z*jver8S|gbF7kbVTS|p0WRF zXFY|3Fc1!u00kO`0(D=6+sf78wyuvYU?2%Rly{5RIDrNhJ?7TLl2NSF}? z)0 z(?2F9n|AG&1ez>C18<;1w;%XC(9|2@o@YXE2&P3YhD#n`R;q$c649ldbQ*fD*hgIk zmIv}sYO4{fL;)lMH7l@UhY4o2DX0JDK7GHw<@rZiSPx6BYl+Va=Xk98!@Vdx&&_Ba z;57NQxCr74eBYBJD?a>E(tcSZWtrI$7YT(KCI)7^^ps=TKs_EMu27dL@YMFfq6x;} zc}N}H{+#|YA#LEJ#ZAjG>E?v`P<*``PU_vw7#eD zdJ?$P$xMM-ujfLpCSTMO{W~U1h(40)h_PD zZY+h5rRc%}{n~0ime`5Ds8uR&0T)8p?uZl?O3}7mviyrVvU4fYr014MbWn&yAP)s| zmlwgv-3UW-s>+!0R4ZDo$XKB`bSJv!M54Y?w~ybPF!a1D4YAe+G5zu1?5H-GyM5hm zxcR9KxdoUYBv=KFVFmO)D=sdC=Mg406h=F;!j-fV3PMF|eT4un)WnAcQV~EygF~g# zQ7B0%CVB1kr=!}m378xy0tWuoivs$aRIf^!+rel zY*_MEL0LjG9b!l|j$jYXUZ^N3Mnv68Xr$fXPOHFu_Py|8Nj&#FkuF`3HUvOrBMiG# zWPDog`zQjSCl6$$ip#}4aDT<|X>_TEKK1kWfU0qm{7*b2pF}?&a!i!HQodOQB^U!% z(BR5~DCb%*6@Y^Q_uZE%dw*OeE57?diuYt8^)sTsyI=>2%4m92yExD;2bQ)b*uR>c z9>^8Lq@Wy{YS=LOqC;iyHN%U#kG*D;M4EpxyvR6 zMJ0%TfIhRRWjYyf^ds1+%(Qaz_e$^6I!Kr99c9n%3`s`>DXR&SAB4Of_?mh>RRGg` z89QO<#Cz_!=ozh|!2bXRj-3K0C4lPW@a5-+%f_@%w!HP;#k*lB-Ui&J8G)7!P!!Q9 z+)HkS!av2eXaO~xjC#-Iq8F(su-wlncS<3azllA2NXs+&O54E$McTH4(Il42#71S5 zjx8xkS){^C^#ePIV1PgZs&?QY94XJy_)V&-w2H9obVB=s+RAmZd+i1>F*|9QLqY(k6ilf5qRpHj$ZfMQ?3^1MrZF5|TBth&Ty;iHu9%|3 zrOTQ9A&)FU(!R5Owagv=@u~AkyyU-8IfM-2SAY!&$!1G zeD4Em5)?~e)Xal>RH4^Q08@r3 zQy+pSfC?{X5R=nk!RrMV>VdmnF=UPT6^J&3z!C9n+emDy*3zPXUy*K|RUUH*hfOKv zriyWM0iIbDnrd6By7Bw>94PTh0|o7TJQ6H9vF^rt8e60%5pdA5V~=F6T`yaguaW|A zoyB>1Fgfx_1iXyMY4YRs_lfdOdJIwdLI5Rr^0<%U3jlv1!m;HbeQUC~ z=yw;=2E!bz`ITRPb-j4wEssAO9+fC%BV9kTz{%z;kGYQnfb2fHc|cF!GzSTZ3hdQwLAW|{Qb-KSlC`RR~#1WJGc$4-Hh9zb={ z_|nsDQek-Rw-;Z2uypfg2~mm8U>~Zq^loK1PR#1bImZm*M_&PItWI{rM zHY>a%MJP#^tYE5 z7fhM*c}PNHOT~q7Uf_k7TnB(A|;yR5`Y`CQqN%9Jz z$SOk&O_c^1Hb&H#6ZH5A!MS0O$Z$A zt?NT4ke6IcDKRqO^2_r2UvcRb=G4@mnp)1O+WZIq&_-uwq3_Z)Yt}4IPs^1c8)AM^ zi~&i50p3OePCAakv!OPtTNSP?1ugolSvKgtg$tKYvcW9N8eAe1pTA{C-=0Ye>z*I@ z9iYI`Qb1>ij`q3}{(N6XUT0bO{YNW5{Ipla-aX5*z%yc?sh6B!>A^n&nj7G%w%m!Lu2cVDlL|m)#!&|6HLLs5WQRbA z56=ax^FNp5+Wj=oAO)Z}llwHVh1dZXxT(m3Re=F0pXaC$GsFwM1`a6bIsTgKq+9E6 z0W9cY!xi+)P+BU{Sy}FGtJkh+yL$C%tIzGq?bfaRk2l>k?03L+w0CCx-^|UN|KyXC zE@HY2idekhB*}rgy!rCLgEtG7;~gUolV9nRPnHJfXO;9AbWvwhkIt=Df(Fe-)_b({ z2%O)1D1cY*)Gd55!TxosT(DsB+HdC%D&De9qTvc^b>QU$SrB3aD{R<})&fqAT9lRI zJ@!*iae+Jl_RwTQ;9YQ-4BkO)zY#7!1Wx{@;>rTUa1-rQQ49!lLOCmsGXWl#;|6l4 z06?z9wLC)va{j<^G)gmohlx13Pl_B=8#Leqj3ShuU2@Axr3ABpF(y=cUwmF(p9{|& zCw+P>0BC6Ft?pj`e~Nx0r!8EVJ>#=a7k2n{%|@g$h8Y-Quevz?v3DN1u|J`-hrtafD*h}`~a$=B;h=QHX})S zuw~#6$~Sq;1btNscS9bh*8gN0m9mI{sA=`N%w|yl3{b58 zO{64Xa@kGT1%MJq&9K!Zhw25(Ns$2K&2h{8PCVZX6Du!dn?-OE$isboNiouSaDP{q zvj+Y>woS@ghSse!dFJsb08iuMr3DKnKK_3fWMw)fEHoONpiwHSD&Uv^86_O>z1~vT z_NU9BGrRVj`qm@s8=@V&@4x@OcsJXmFLDsIIK8I~9C+H)#3ARuA}yje zHS{tajr(0$vV89Y_ul=|1*JtnuuNzV6CnV*s|5b$F4$z|NNIUK%vLKUD#}(he#|x7 z0ieID<5+f(lP)dwUHI*{3$yp{tyC_YTorg=vzwEj4G*P~;A5#ba7};$$4Y?!2YLjQ z1IQWhc1B9t-hPgq+iuFYcDX#eSGbRl$5JqqqdCRm8Up#gY~7i;)N}oYJ}D?yhI_ zn`G(SWsW37>}d?pR1L3~v<#L73tx%=E$S_AZK!qz z>N)u-5a2+M;2GnkB%4SeSild!?z-0d_eV+E{;sk=_w35u8N>H)-7z39W4}~@Lv_P^ z$Om^y76VYysMhV8(nsyA^$)93^$Uz8WT!|$f^@k-;lW~$jlwoex~H_*9oI5>UQ*|d z3lT+Qm2_^Mf%X8ho2GpJ&eF@$)AJ=hwyiS3a(l|bU02G*7Y~pdZWuMIZF|!bAwjYk zZ9HyT?kh(0`(*2;U1!ai_2b~wySRnfM?T;iBtKm0S>f*p1yD5M58?Y zv{iQPijea11b0C}qNB7tsU)u`wX(Dg75>epOt}4D^H#3hbFtA70x<@B%-v;j&N+SL z)k#)p5O2Q6F3jQaEq^&58V zE;=_nG^}N?)igIO%#hP;h!kkZDMNt(2iic7+AwjVS0+xR{FI+8eAYEk)y=A!@>17X z^fC<%F++)Fm%Q9O6&VS+>+%X6zShMB-pgRlbmu*Pez(i^E&C-mD^Il_(M2H_HA-PY zk#yFa6goI?Brerw1s|pcDuIXoHgT z9r^fF91OTqf(U_fVp1RgpeN>YYqC~{hlDH)G8?b*xGEvvGV8mJ#9Mkbr1Xg(c+@8y+vk`GxYIe|_*7xX?&&lgCY7+GKEVM?6^R4hL9VJC1W4J9$b7k2z84}e zl@>)_ITz5B3!LkQ&D+mBfyohQ`YBF$Bm+w5uCF(^AKSPEd0PzGMp7ThClNmN95VrD5ksnB{a#h&;e+~1}q?M&e20SeTE z0s%YFdJr#g>ES5=1reQ52bWaHd#_BIpZfm$vm`b;6|q!pSo)Vi1W+U&PW@;54m}Jz z4qsE?Xn+FElL7$_w0S<46S`FZ&ag_CT${dEUjJp)#^4X8&z9eQ+bv1S?Zk!Tcy2F) zf0RkzJ{`pzD*I39&ITHPN>d=ffu7Qjzu`I$&@?PvTGVUFlC>{XIgOX3?@5zQTQ?)r zoD(0nBqq`I6QTNyE-5d~m6!;TDet^e)S+EaKnB`yk0DS~BU2#2fi^P1PuANlTUK!K zop(Myx1!Rj%$iI=2)Sp4Srb@HtJNtb#bvMqMWAWK355r%Jn{5X(z2~(&dExTK)+56 z3IxoUPL1b$+ 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.525.0) - aws-sigv4 (~> 1.1) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.58.0) - aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-kms (1.59.0) + aws-sdk-core (~> 3, >= 3.165.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.114.0) - aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-s3 (1.117.1) + aws-sdk-core (~> 3, >= 3.165.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.1) + aws-sigv4 (1.5.2) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) @@ -36,7 +36,7 @@ GEM unf (>= 0.0.5, < 1.0.0) dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.92.4) + excon (0.94.0) faraday (1.10.2) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -66,7 +66,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.6) - fastlane (2.209.1) + fastlane (2.211.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -106,9 +106,9 @@ GEM xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.25.0) - google-apis-core (>= 0.7, < 2.a) - google-apis-core (0.7.0) + google-apis-androidpublisher_v3 (0.31.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-core (0.9.1) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -117,27 +117,27 @@ GEM retriable (>= 2.0, < 4.a) rexml webrick - google-apis-iamcredentials_v1 (0.13.0) - google-apis-core (>= 0.7, < 2.a) - google-apis-playcustomapp_v1 (0.10.0) - google-apis-core (>= 0.7, < 2.a) - google-apis-storage_v1 (0.17.0) - google-apis-core (>= 0.7, < 2.a) + google-apis-iamcredentials_v1 (0.16.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-playcustomapp_v1 (0.12.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-storage_v1 (0.19.0) + google-apis-core (>= 0.9.0, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.2.0) - google-cloud-storage (1.39.0) + google-cloud-errors (1.3.0) + google-cloud-storage (1.44.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.17.0) + google-apis-storage_v1 (~> 0.19.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.2.0) + googleauth (1.3.0) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) memoist (~> 0.16) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 41ebedb1..0c6ae0ff 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -392,7 +392,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 42; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -426,7 +426,7 @@ CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 42; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -475,7 +475,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 42; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -534,7 +534,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 42; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -570,7 +570,7 @@ CODE_SIGN_IDENTITY = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 42; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -600,7 +600,7 @@ CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 42; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 50c0818d..bde4e4b2 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -23,7 +23,7 @@ CFBundleSignature ???? CFBundleVersion - 40 + 42 LSRequiresIPhoneOS LSSupportsOpeningDocumentsInPlace diff --git a/lib/src/models/home_screen_feed_models/home_feed.dart b/lib/src/models/home_screen_feed_models/home_feed.dart index df79dee9..0a37595d 100644 --- a/lib/src/models/home_screen_feed_models/home_feed.dart +++ b/lib/src/models/home_screen_feed_models/home_feed.dart @@ -37,6 +37,7 @@ class HomeFeedItem { final String playUrl; final String ipfs; final HomeFeedItemImage images; + final bool isReel; HomeFeedItem({ this.created = "", @@ -52,6 +53,7 @@ class HomeFeedItem { this.playUrl = "", this.ipfs = "", required this.images, + required this.isReel, }); String getVideoUrl(HiveUserData data) { @@ -86,6 +88,7 @@ class HomeFeedItem { isIpfs: asBool(json, 'isIpfs'), playUrl: asString(json, 'playUrl'), ipfs: asString(json, 'ipfs'), + isReel: asBool(json, 'isReel'), images: HomeFeedItemImage.fromJson(asMap(json, 'images')), ); @@ -102,6 +105,7 @@ class HomeFeedItem { 'isIpfs': isIpfs, 'playUrl': playUrl, 'ipfs': ipfs, + 'isReel': isReel, 'images': images.toJson(), }; } diff --git a/lib/src/screens/stories/stories_feed.dart b/lib/src/screens/stories/stories_feed.dart new file mode 100644 index 00000000..c000a571 --- /dev/null +++ b/lib/src/screens/stories/stories_feed.dart @@ -0,0 +1,143 @@ +import 'dart:io'; + +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:acela/src/widgets/story_player.dart'; +import 'package:acela/src/widgets/story_player_android.dart'; +import 'package:carousel_slider/carousel_slider.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; +import 'package:provider/provider.dart'; + +class StoriesFeedScreen extends StatefulWidget { + const StoriesFeedScreen({ + Key? key, + required this.type, + }) : super(key: key); + final String type; + + @override + State createState() => _StoriesFeedScreenState(); +} + +class _StoriesFeedScreenState extends State { + List items = []; + var isLoading = false; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + setState(() { + isLoading = true; + }); + var response = await get( + Uri.parse('${server.domain}/apiv2/feeds/${widget.type}?isReel=true')); + if (response.statusCode == 200) { + List list = homeFeedItemFromString(response.body); + setState(() { + isLoading = false; + items = list.where((element) => element.duration < 300).toList(); + }); + } else { + showError('Status code ${response.statusCode}'); + setState(() { + isLoading = false; + items = []; + }); + } + } + + void showError(String string) { + var snackBar = SnackBar(content: Text('Error: $string')); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + void showMessage(String string) { + var snackBar = SnackBar(content: Text(string)); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + Widget loadingData() { + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); + } + + Widget _fullPost(HomeFeedItem item, HiveUserData data) { + return Platform.isAndroid + ? Stack( + children: [ + StoryPlayerAndroid( + playUrl: item.getVideoUrl(data), + thumbnail: item.images.thumbnail, + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + ), + Container( + child: Row( + children: [ + const Spacer(), + Text('@${item.author}/${item.permlink}', + style: Theme.of(context).textTheme.titleLarge), + const Spacer(), + ], + ), + ) + ], + ) + : Stack( + children: [ + StoryPlayer( + playUrl: item.getVideoUrl(data), + thumbnail: item.images.thumbnail, + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + ), + Container( + child: Row( + children: [ + const Spacer(), + Text('@${item.author}/${item.permlink}', + style: Theme.of(context).textTheme.titleLarge), + const Spacer(), + ], + ), + ) + ], + ); + } + + Widget carousel(HiveUserData data) { + return Container( + child: CarouselSlider( + options: CarouselOptions( + height: MediaQuery.of(context).size.height, + enableInfiniteScroll: false, + viewportFraction: 1, + scrollDirection: Axis.vertical, + // enlargeCenterPage: true, + ), + items: items.map((item) { + return Builder( + builder: (BuildContext context) { + return _fullPost(item, data); + }, + ); + }).toList(), + ), + ); + } + + @override + Widget build(BuildContext context) { + var userData = Provider.of(context); + return isLoading ? loadingData() : carousel(userData); + } +} diff --git a/lib/src/screens/stories/stories_screen.dart b/lib/src/screens/stories/stories_screen.dart index d5436ca9..e8d2b7f3 100644 --- a/lib/src/screens/stories/stories_screen.dart +++ b/lib/src/screens/stories/stories_screen.dart @@ -1,15 +1,5 @@ -import 'dart:io'; - -import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; -import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/widgets/loading_screen.dart'; -import 'package:acela/src/widgets/story_player.dart'; -import 'package:acela/src/widgets/story_player_android.dart'; -import 'package:carousel_slider/carousel_slider.dart'; +import 'package:acela/src/screens/stories/stories_feed.dart'; import 'package:flutter/material.dart'; -import 'package:http/http.dart'; -import 'package:provider/provider.dart'; class StoriesScreen extends StatefulWidget { const StoriesScreen({Key? key}) : super(key: key); @@ -19,110 +9,55 @@ class StoriesScreen extends StatefulWidget { } class _StoriesScreenState extends State { - List items = []; - var isLoading = false; - // Map payout = {}; - // var isFabLoading = false; + static const List tabs = [ + Tab( + // text: 'Trending', + icon: const Icon(Icons.local_fire_department), + ), + Tab( + // text: 'New', + icon: const Icon(Icons.play_arrow), + ), + Tab( + // text: 'First Time', + icon: const Icon(Icons.emoji_emotions_outlined), + ), + ]; @override - void initState() { - super.initState(); - loadData(); - } - - void loadData() async { - setState(() { - isLoading = true; - }); - var response = - await get(Uri.parse('${server.domain}/apiv2/feeds/trending')); - if (response.statusCode == 200) { - List list = homeFeedItemFromString(response.body); - setState(() { - isLoading = false; - items = list; - }); - // var i = 0; - // while (i < list.length) { - // if (mounted) { - // var info = await Communicator() - // .fetchHiveInfo(list[i].author, list[i].permlink); - // setState(() { - // payout["${list[i].author}/${list[i].permlink}"] = info; - // i++; - // }); - // } else { - // break; - // } - // } - } else { - showError('Status code ${response.statusCode}'); - setState(() { - isLoading = false; - items = []; - }); - } - } - - void showError(String string) { - var snackBar = SnackBar(content: Text('Error: $string')); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - - void showMessage(String string) { - var snackBar = SnackBar(content: Text('Message: $string')); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - - Widget loadingData() { - return const LoadingScreen( - title: 'Loading Data', - subtitle: 'Please wait', - ); - } - - Widget _fullPost(HomeFeedItem item, HiveUserData data) { - return Platform.isAndroid - ? StoryPlayerAndroid( - playUrl: item.getVideoUrl(data), - thumbnail: item.images.thumbnail, - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, - ) - : StoryPlayer( - playUrl: item.getVideoUrl(data), - thumbnail: item.images.thumbnail, - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, - ); - } - - Widget carousel(HiveUserData data) { - return Container( - child: CarouselSlider( - options: CarouselOptions( - height: MediaQuery.of(context).size.height, - enableInfiniteScroll: false, - viewportFraction: 1, - scrollDirection: Axis.vertical, - // enlargeCenterPage: true, - ), - items: items.map((item) { - return Builder( - builder: (BuildContext context) { - return _fullPost(item, data); - }, + Widget build(BuildContext context) { + return DefaultTabController( + length: tabs.length, + child: Builder( + builder: (context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: Row( + children: [ + Image.asset( + "assets/branding/three_shorts_icon.png", + width: 40, + height: 40, + ), + const SizedBox(width: 15), + const Text('3Shorts') + ], + ), + bottom: TabBar( + tabs: tabs, + ), + ), + body: TabBarView( + children: [ + StoriesFeedScreen(type: 'trending'), + StoriesFeedScreen(type: 'new'), + StoriesFeedScreen(type: 'firstUploads'), + ], + ), ); - }).toList(), + }, ), ); } - - @override - Widget build(BuildContext context) { - var userData = Provider.of(context); - return Scaffold( - body: isLoading ? loadingData() : carousel(userData), - ); - } } diff --git a/lib/src/widgets/story_player.dart b/lib/src/widgets/story_player.dart index 041a8d4d..099cfd3d 100644 --- a/lib/src/widgets/story_player.dart +++ b/lib/src/widgets/story_player.dart @@ -33,7 +33,7 @@ class _StoryPlayerState extends State { BetterPlayerConfiguration betterPlayerConfiguration = BetterPlayerConfiguration( aspectRatio: widget.width / widget.height, - fit: BoxFit.fill, + fit: BoxFit.fitHeight, autoPlay: true, // fullScreenByDefault: true, controlsConfiguration: BetterPlayerControlsConfiguration( diff --git a/pubspec.lock b/pubspec.lock index a2948eb2..4d271479 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,322 +5,368 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + sha256: "3444216bfd127af50bbe4862d8843ed44db946dd933554f0d7285e89f10e28ac" + url: "https://pub.dev" source: hosted version: "50.0.0" adaptive_action_sheet: dependency: "direct main" description: name: adaptive_action_sheet - url: "https://pub.dartlang.org" + sha256: "2cf53889102f2f476d03da30ef4219a3199f1d9b9f7bf063e2b23cd5aa88ea02" + url: "https://pub.dev" source: hosted version: "2.0.2" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + sha256: "68796c31f510c8455a06fed75fc97d8e5ad04d324a830322ab3efc9feb6201c1" + url: "https://pub.dev" source: hosted version: "5.2.0" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 + url: "https://pub.dev" source: hosted version: "2.3.1" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" base_x: dependency: transitive description: name: base_x - url: "https://pub.dartlang.org" + sha256: "3f1043679659f1759c651f900da6f24f0a8062c28daa6f9625e8d580002e187b" + url: "https://pub.dev" source: hosted version: "2.0.0" better_player: dependency: "direct main" description: name: better_player - url: "https://pub.dartlang.org" + sha256: f2e5d57ea49fb7c4d93838d23846ca5ddf78af6f946e103aeacf2afdd01909b3 + url: "https://pub.dev" source: hosted version: "0.0.83" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" bs58: dependency: "direct main" description: name: bs58 - url: "https://pub.dartlang.org" + sha256: "3ed24dadf386ca749ff50af678be1131ef569a3583a6f37b87b90c032270c767" + url: "https://pub.dev" source: hosted version: "1.0.2" bs58check: dependency: "direct main" description: name: bs58check - url: "https://pub.dartlang.org" + sha256: c4a164d42b25c2f6bc88a8beccb9fc7d01440f3c60ba23663a20a70faf484ea9 + url: "https://pub.dev" source: hosted version: "1.0.2" buffer: dependency: transitive description: name: buffer - url: "https://pub.dartlang.org" + sha256: "850b666e7d27c5cf42f39c43d3a9d37b7b35519b9715d9f85b418d76201518c6" + url: "https://pub.dev" source: hosted version: "1.1.1" build: dependency: transitive description: name: build - url: "https://pub.dartlang.org" + sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" + url: "https://pub.dev" source: hosted version: "2.3.1" build_config: dependency: transitive description: name: build_config - url: "https://pub.dartlang.org" + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" source: hosted version: "1.1.1" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.dartlang.org" + sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf" + url: "https://pub.dev" source: hosted version: "3.1.0" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.dartlang.org" + sha256: "7c35a3a7868626257d8aee47b51c26b9dba11eaddf3431117ed2744951416aab" + url: "https://pub.dev" source: hosted version: "2.1.0" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.dartlang.org" + sha256: "6f48c61a9dcd2c3a9e62d3dcdab1ba382790e2f31026288cbabe55d6003c9c23" + url: "https://pub.dev" source: hosted version: "2.3.2" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.dartlang.org" + sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292" + url: "https://pub.dev" source: hosted version: "7.2.7" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.dartlang.org" + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.dartlang.org" + sha256: "59e08b0079bb75f7e27392498e26339387c1089c6bd58525a14eb8508637277b" + url: "https://pub.dev" source: hosted version: "8.4.2" carousel_slider: dependency: "direct main" description: name: carousel_slider - url: "https://pub.dartlang.org" + sha256: "869a3f4f2ad0e8d029d9cefd20d2cafd0a50847b74e7aab3a8eec662b0c7d2ee" + url: "https://pub.dev" source: hosted version: "4.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted version: "1.2.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + sha256: dd007e4fb8270916820a0d66e24f619266b60773cddd082c6439341645af2659 + url: "https://pub.dev" source: hosted version: "2.0.1" chewie: dependency: "direct main" description: name: chewie - url: "https://pub.dartlang.org" + sha256: edb7a38d3f80035e46f931a6ff9391706e206f81f7c00ca4d58356809b593427 + url: "https://pub.dev" source: hosted version: "1.3.5" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.dartlang.org" + sha256: "02ce3596b459c666530f045ad6f96209474e8fee6e4855940a3cee65fb872ec5" + url: "https://pub.dev" source: hosted version: "4.3.0" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" source: hosted version: "3.1.1" cross_file: dependency: transitive description: name: cross_file - url: "https://pub.dartlang.org" + sha256: f71079978789bc2fe78d79227f1f8cfe195b31bbd8db2399b0d15a4b96fb843b + url: "https://pub.dev" source: hosted version: "0.3.3+2" crypto: dependency: "direct main" description: name: crypto - url: "https://pub.dartlang.org" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" source: hosted version: "3.0.2" csslib: dependency: transitive description: name: csslib - url: "https://pub.dartlang.org" + sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 + url: "https://pub.dev" source: hosted version: "0.17.2" cupertino_icons: dependency: transitive description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" + url: "https://pub.dev" source: hosted version: "2.2.4" device_info_plus: dependency: "direct main" description: name: device_info_plus - url: "https://pub.dartlang.org" + sha256: b809c4ed5f7fcdb325ccc70b80ad934677dc4e2aa414bf46859a42bfdfafcbb6 + url: "https://pub.dev" source: hosted version: "4.1.3" device_info_plus_linux: dependency: transitive description: name: device_info_plus_linux - url: "https://pub.dartlang.org" + sha256: "77a8b3c4af06bc46507f89304d9f49dfc64b4ae004b994532ed23b34adeae4b3" + url: "https://pub.dev" source: hosted version: "3.0.0" device_info_plus_macos: dependency: transitive description: name: device_info_plus_macos - url: "https://pub.dartlang.org" + sha256: "37961762fbd46d3620c7b69ca606671014db55fc1b7a11e696fd90ed2e8fe03d" + url: "https://pub.dev" source: hosted version: "3.0.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - url: "https://pub.dartlang.org" + sha256: "83fdba24fcf6846d3b10f10dfdc8b6c6d7ada5f8ed21d62ea2909c2dfa043773" + url: "https://pub.dev" source: hosted version: "3.0.0" device_info_plus_web: dependency: transitive description: name: device_info_plus_web - url: "https://pub.dartlang.org" + sha256: "5890f6094df108181c7a29720bc23d0fd6159f17d82787fac093d1fefcaf6325" + url: "https://pub.dev" source: hosted version: "3.0.0" device_info_plus_windows: dependency: transitive description: name: device_info_plus_windows - url: "https://pub.dartlang.org" + sha256: "23a2874af0e23ee6e3a2a0ebcecec3a9da13241f2cb93a93a44c8764df123dd7" + url: "https://pub.dev" source: hosted version: "4.1.0" elliptic: dependency: "direct main" description: name: elliptic - url: "https://pub.dartlang.org" + sha256: "8c7396126c81c574fe970ac4afe9ba919b1ca754da20b509664be2345ffb2845" + url: "https://pub.dev" source: hosted version: "0.3.8" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + url: "https://pub.dev" source: hosted version: "2.0.1" ffmpeg_kit_flutter: dependency: "direct main" description: name: ffmpeg_kit_flutter - url: "https://pub.dartlang.org" + sha256: d915ccb87b7e99e4de8112e0c32e42f5dd3cd7a22ad4340fa13aac12e87beb98 + url: "https://pub.dev" source: hosted version: "4.5.1" ffmpeg_kit_flutter_platform_interface: dependency: transitive description: name: ffmpeg_kit_flutter_platform_interface - url: "https://pub.dartlang.org" + sha256: addf046ae44e190ad0101b2fde2ad909a3cd08a2a109f6106d2f7048b7abedee + url: "https://pub.dev" source: hosted version: "0.2.1" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" source: hosted version: "6.1.4" file_picker: dependency: "direct main" description: name: file_picker - url: "https://pub.dartlang.org" + sha256: c24465c112b1a31a37ac450afc2e1f927b7c11599beab93233d7ffb449373fe3 + url: "https://pub.dev" source: hosted version: "5.2.2" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + sha256: "04be3e934c52e082558cc9ee21f42f5c1cd7a1262f4c63cd0357c08d5bba81ec" + url: "https://pub.dev" source: hosted version: "1.0.1" flutter: @@ -332,70 +378,80 @@ packages: dependency: "direct main" description: name: flutter_dotenv - url: "https://pub.dartlang.org" + sha256: d9283d92059a22e9834bc0a31336658ffba77089fb6f3cc36751f1fc7c6661a3 + url: "https://pub.dev" source: hosted version: "5.0.2" flutter_lints: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted version: "2.0.1" flutter_markdown: dependency: "direct main" description: name: flutter_markdown - url: "https://pub.dartlang.org" + sha256: "981442432b632237ffc1cf8092b4173b9e9f2278b5740637287c3069b51c8f09" + url: "https://pub.dev" source: hosted - version: "0.6.12" + version: "0.6.13" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" + url: "https://pub.dev" source: hosted version: "2.0.7" flutter_secure_storage: dependency: "direct main" description: name: flutter_secure_storage - url: "https://pub.dartlang.org" + sha256: a12d0213eab6848033b824fce82ef33229ec638debae46ef3d570d8b1146949b + url: "https://pub.dev" source: hosted version: "6.0.0" flutter_secure_storage_linux: dependency: transitive description: name: flutter_secure_storage_linux - url: "https://pub.dartlang.org" + sha256: "7b36defaed0a994cc58d6a169a7c89c695ea660ef86903df13c2a2708fb1e1bb" + url: "https://pub.dev" source: hosted version: "1.1.1" flutter_secure_storage_macos: dependency: transitive description: name: flutter_secure_storage_macos - url: "https://pub.dartlang.org" + sha256: cd8eff6ebb4d9083aa3a57f29da00df837a869e8d5c65d9ad1ce549037c55d06 + url: "https://pub.dev" source: hosted version: "1.1.1" flutter_secure_storage_platform_interface: dependency: transitive description: name: flutter_secure_storage_platform_interface - url: "https://pub.dartlang.org" + sha256: "9af003dec5ba9f959300fd76ac8adf5608fbfbc957cdd7a987af206a8e073b32" + url: "https://pub.dev" source: hosted version: "1.0.0" flutter_secure_storage_web: dependency: transitive description: name: flutter_secure_storage_web - url: "https://pub.dartlang.org" + sha256: "926716d84eb45220cb1783af629093301613f5e5b51da7c1813e430d69bd716f" + url: "https://pub.dev" source: hosted version: "1.0.2" flutter_secure_storage_windows: dependency: transitive description: name: flutter_secure_storage_windows - url: "https://pub.dartlang.org" + sha256: cf9fd49c2807f80dc01f449592e1e7971a3697d1e248b653efb8323536dc2961 + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_test: @@ -412,443 +468,506 @@ packages: dependency: transitive description: name: flutter_widget_from_html_core - url: "https://pub.dartlang.org" + sha256: e8f4f8b461a140ffb7c71f938bc76efc758893e7468843d9dbf70cb0b9e900cb + url: "https://pub.dev" source: hosted version: "0.8.5+3" font_awesome_flutter: dependency: "direct main" description: name: font_awesome_flutter - url: "https://pub.dartlang.org" + sha256: "8f0ce0204bd0cafa8631536a6f3b7d05d9c16cdc6e8bd807843f917027c5cefd" + url: "https://pub.dev" source: hosted version: "10.2.1" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + sha256: "82715f8041a85a534a7bf64400b2ee0bb3d594ccf695d97c0bb017259657ff5d" + url: "https://pub.dev" source: hosted version: "3.1.0" fwfh_text_style: dependency: transitive description: name: fwfh_text_style - url: "https://pub.dartlang.org" + sha256: "37806ee0222f79b6e8d4c698c322c897eae6a817258156f40aeece4e588fac60" + url: "https://pub.dev" source: hosted version: "2.22.08+1" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" graphs: dependency: transitive description: name: graphs - url: "https://pub.dartlang.org" + sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2 + url: "https://pub.dev" source: hosted version: "2.2.0" hex: dependency: "direct main" description: name: hex - url: "https://pub.dartlang.org" + sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a" + url: "https://pub.dev" source: hosted version: "0.2.0" html: dependency: transitive description: name: html - url: "https://pub.dartlang.org" + sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 + url: "https://pub.dev" source: hosted version: "0.15.1" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" source: hosted version: "0.13.5" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" source: hosted version: "4.0.2" image_picker: dependency: "direct main" description: name: image_picker - url: "https://pub.dartlang.org" + sha256: a8f2f0aed50c03230ab37e93ca2905c50b6c4097245345956eb24a88f45328cd + url: "https://pub.dev" source: hosted version: "0.8.6" image_picker_android: dependency: transitive description: name: image_picker_android - url: "https://pub.dartlang.org" + sha256: "822f71a53336bf1e638dbf955047080ca49ba0197f52c4fece9cf584c368648a" + url: "https://pub.dev" source: hosted version: "0.8.5+3" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - url: "https://pub.dartlang.org" + sha256: "7d319fb74955ca46d9bf7011497860e3923bb67feebcf068f489311065863899" + url: "https://pub.dev" source: hosted version: "2.1.10" image_picker_ios: dependency: transitive description: name: image_picker_ios - url: "https://pub.dartlang.org" + sha256: "1768087441bd69ca632249d212c26fa8d530552d37b4896a4dd8d6781435c147" + url: "https://pub.dev" source: hosted version: "0.8.6+1" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - url: "https://pub.dartlang.org" + sha256: "7cef2f28f4f2fef99180f636c3d446b4ccbafd6ba0fad2adc9a80c4040f656b8" + url: "https://pub.dev" source: hosted version: "2.6.2" images_picker: dependency: "direct main" description: name: images_picker - url: "https://pub.dartlang.org" + sha256: cc99347a6fa93228bf92f15ce36e4474256e4af0e6c0e1f0e7e9f047adbccd5b + url: "https://pub.dev" source: hosted version: "1.2.11" intl: dependency: "direct main" description: name: intl - url: "https://pub.dartlang.org" + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + url: "https://pub.dev" source: hosted version: "0.17.0" io: dependency: transitive description: name: io - url: "https://pub.dartlang.org" + sha256: "0d4c73c3653ab85bf696d51a9657604c900a370549196a91f33e4c39af760852" + url: "https://pub.dev" source: hosted version: "1.0.3" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" json_annotation: dependency: "direct main" description: name: json_annotation - url: "https://pub.dartlang.org" + sha256: "3520fa844009431b5d4491a5a778603520cdc399ab3406332dcc50f93547258c" + url: "https://pub.dev" source: hosted version: "4.7.0" json_serializable: dependency: "direct dev" description: name: json_serializable - url: "https://pub.dartlang.org" + sha256: f3c2c18a7889580f71926f30c1937727c8c7d4f3a435f8f5e8b0ddd25253ef5d + url: "https://pub.dev" source: hosted version: "6.5.4" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" source: hosted version: "2.0.1" localstorage: dependency: "direct main" description: name: localstorage - url: "https://pub.dartlang.org" + sha256: "93f103074c0661bc1bb90aa88e172ee2e9096ec0c4f9baf519e23372c39ca681" + url: "https://pub.dev" source: hosted version: "4.0.0+1" logging: dependency: transitive description: name: logging - url: "https://pub.dartlang.org" + sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946 + url: "https://pub.dev" source: hosted version: "1.1.0" markdown: dependency: transitive description: name: markdown - url: "https://pub.dartlang.org" + sha256: c2b81e184067b41d0264d514f7cdaa2c02d38511e39d6521a1ccc238f6d7b3f2 + url: "https://pub.dev" source: hosted version: "6.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted version: "1.8.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + sha256: dab22e92b41aa1255ea90ddc4bc2feaf35544fd0728e209638cad041a6e3928a + url: "https://pub.dev" source: hosted version: "1.0.2" nested: dependency: transitive description: name: nested - url: "https://pub.dartlang.org" + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" source: hosted version: "1.0.0" overlay_support: dependency: "direct main" description: name: overlay_support - url: "https://pub.dartlang.org" + sha256: fc39389bfd94e6985e1e13b2a88a125fc4027608485d2d4e2847afe1b2bb339c + url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.0" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" source: hosted version: "2.1.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted version: "1.8.2" path_provider: dependency: "direct main" description: name: path_provider - url: "https://pub.dartlang.org" + sha256: "050e8e85e4b7fecdf2bb3682c1c64c4887a183720c802d323de8a5fd76d372dd" + url: "https://pub.dev" source: hosted version: "2.0.11" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.dartlang.org" + sha256: "1dab723dd8feeb80afb39c7be894f09df1457243d930010f6f328fb8c660c5e1" + url: "https://pub.dev" source: hosted version: "2.0.21" path_provider_ios: dependency: transitive description: name: path_provider_ios - url: "https://pub.dartlang.org" + sha256: "03d639406f5343478352433f00d3c4394d52dac8df3d847869c5e2333e0bbce8" + url: "https://pub.dev" source: hosted version: "2.0.11" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 + url: "https://pub.dev" source: hosted version: "2.1.7" path_provider_macos: dependency: transitive description: name: path_provider_macos - url: "https://pub.dartlang.org" + sha256: "2a97e7fbb7ae9dcd0dfc1220a78e9ec3e71da691912e617e8715ff2a13086ae8" + url: "https://pub.dev" source: hosted version: "2.0.6" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + url: "https://pub.dev" source: hosted version: "2.0.5" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c + url: "https://pub.dev" source: hosted version: "2.1.3" permission_handler: dependency: "direct main" description: name: permission_handler - url: "https://pub.dartlang.org" + sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8" + url: "https://pub.dev" source: hosted version: "10.2.0" permission_handler_android: dependency: transitive description: name: permission_handler_android - url: "https://pub.dartlang.org" + sha256: "8028362b40c4a45298f1cbfccd227c8dd6caf0e27088a69f2ba2ab15464159e2" + url: "https://pub.dev" source: hosted version: "10.2.0" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - url: "https://pub.dartlang.org" + sha256: "9c370ef6a18b1c4b2f7f35944d644a56aa23576f23abee654cf73968de93f163" + url: "https://pub.dev" source: hosted version: "9.0.7" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - url: "https://pub.dartlang.org" + sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" + url: "https://pub.dev" source: hosted version: "3.9.0" permission_handler_windows: dependency: transitive description: name: permission_handler_windows - url: "https://pub.dartlang.org" + sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b + url: "https://pub.dev" source: hosted version: "0.1.2" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + url: "https://pub.dev" source: hosted version: "5.1.0" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + url: "https://pub.dev" source: hosted version: "2.1.3" pointycastle: dependency: transitive description: name: pointycastle - url: "https://pub.dartlang.org" + sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 + url: "https://pub.dev" source: hosted version: "3.6.2" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" source: hosted version: "1.5.1" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" source: hosted version: "4.2.4" provider: dependency: "direct main" description: name: provider - url: "https://pub.dartlang.org" + sha256: e1e7413d70444ea3096815a60fe5da1b11bda8a9dc4769252cc82c53536f8bcc + url: "https://pub.dev" source: hosted version: "6.0.4" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dartlang.org" + sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.dartlang.org" + sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" + url: "https://pub.dev" source: hosted version: "1.2.1" share_plus: dependency: "direct main" description: name: share_plus - url: "https://pub.dartlang.org" + sha256: f582d5741930f3ad1bf0211d358eddc0508cc346e5b4b248bd1e569c995ebb7a + url: "https://pub.dev" source: hosted version: "4.5.3" share_plus_linux: dependency: transitive description: name: share_plus_linux - url: "https://pub.dartlang.org" + sha256: dc32bf9f1151b9864bb86a997c61a487967a08f2e0b4feaa9a10538712224da4 + url: "https://pub.dev" source: hosted version: "3.0.1" share_plus_macos: dependency: transitive description: name: share_plus_macos - url: "https://pub.dartlang.org" + sha256: "44daa946f2845045ecd7abb3569b61cd9a55ae9cc4cbec9895b2067b270697ae" + url: "https://pub.dev" source: hosted version: "3.0.1" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - url: "https://pub.dartlang.org" + sha256: "82ddd4ab9260c295e6e39612d4ff00390b9a7a21f1bb1da771e2f232d80ab8a1" + url: "https://pub.dev" source: hosted version: "3.2.0" share_plus_web: dependency: transitive description: name: share_plus_web - url: "https://pub.dartlang.org" + sha256: eaef05fa8548b372253e772837dd1fbe4ce3aca30ea330765c945d7d4f7c9935 + url: "https://pub.dev" source: hosted version: "3.1.0" share_plus_windows: dependency: transitive description: name: share_plus_windows - url: "https://pub.dartlang.org" + sha256: "3a21515ae7d46988d42130cd53294849e280a5de6ace24bae6912a1bffd757d4" + url: "https://pub.dev" source: hosted version: "3.0.1" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + url: "https://pub.dev" source: hosted version: "1.4.0" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.3" sky_engine: dependency: transitive description: flutter @@ -858,30 +977,34 @@ packages: dependency: transitive description: name: source_gen - url: "https://pub.dartlang.org" + sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d" + url: "https://pub.dev" source: hosted version: "1.2.6" source_helper: dependency: transitive description: name: source_helper - url: "https://pub.dartlang.org" + sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f" + url: "https://pub.dev" source: hosted version: "1.3.3" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" steemdart_ecc: dependency: "direct main" description: @@ -895,310 +1018,354 @@ packages: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted version: "2.1.1" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "862015c5db1f3f3c4ea3b94dc2490363a84262994b88902315ed74be1155612f" + url: "https://pub.dev" source: hosted version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: c9aba3b3dbfe8878845dfab5fa096eb8de7b62231baeeb1cea8e3ee81ca8c6d8 + url: "https://pub.dev" source: hosted - version: "0.4.14" + version: "0.4.15" timeago: dependency: "direct main" description: name: timeago - url: "https://pub.dartlang.org" + sha256: "46c128312ab0ea144b146c0ac6426ddd96810efec2de3fccc425d00179cd8254" + url: "https://pub.dev" source: hosted version: "3.3.0" timing: dependency: transitive description: name: timing - url: "https://pub.dartlang.org" + sha256: c386d07d7f5efc613479a7c4d9d64b03710b03cfaa7e8ad5f2bfb295a1f0dfad + url: "https://pub.dev" source: hosted version: "1.0.0" tus_client: dependency: "direct main" description: name: tus_client - url: "https://pub.dartlang.org" + sha256: "59f6015cd67f7615b30dd8addf27229e4d6f72f24d8ca677a3b22940fcad2dd1" + url: "https://pub.dev" source: hosted version: "1.0.2" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" source: hosted version: "1.3.1" universal_io: dependency: transitive description: name: universal_io - url: "https://pub.dartlang.org" + sha256: "79f78ddad839ee3aae3ec7c01eb4575faf0d5c860f8e5223bc9f9c17f7f03cef" + url: "https://pub.dev" source: hosted version: "2.0.4" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.dartlang.org" + sha256: "3c92b0efb5e9dcb8f846aefabf9f0f739f91682ed486b991ceda51c288e60896" + url: "https://pub.dev" source: hosted - version: "6.1.6" + version: "6.1.7" url_launcher_android: dependency: transitive description: name: url_launcher_android - url: "https://pub.dartlang.org" + sha256: "6f91d30ce9060c204b2dbe728adb300750fa4b228e8f7ed1b961aa1ceb728799" + url: "https://pub.dev" source: hosted - version: "6.0.21" + version: "6.0.22" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - url: "https://pub.dartlang.org" + sha256: "6ba7dddee26c9fae27c9203c424631109d73c8fa26cfa7bc3e35e751cb87f62e" + url: "https://pub.dev" source: hosted version: "6.0.17" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - url: "https://pub.dartlang.org" + sha256: "360fa359ab06bcb4f7c5cd3123a2a9a4d3364d4575d27c4b33468bd4497dd094" + url: "https://pub.dev" source: hosted version: "3.0.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - url: "https://pub.dartlang.org" + sha256: a9b3ea9043eabfaadfa3fb89de67a11210d85569086d22b3854484beab8b3978 + url: "https://pub.dev" source: hosted version: "3.0.1" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - url: "https://pub.dartlang.org" + sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6" + url: "https://pub.dev" source: hosted version: "2.1.1" url_launcher_web: dependency: transitive description: name: url_launcher_web - url: "https://pub.dartlang.org" + sha256: "5669882643b96bb6d5786637cac727c6e918a790053b09245fd4513b8a07df2a" + url: "https://pub.dev" source: hosted version: "2.0.13" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - url: "https://pub.dartlang.org" + sha256: e3c3b16d3104260c10eea3b0e34272aaa57921f83148b0619f74c2eced9b7ef1 + url: "https://pub.dev" source: hosted version: "3.0.1" uuid: dependency: transitive description: name: uuid - url: "https://pub.dartlang.org" + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.0.7" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted version: "2.1.4" video_compress: dependency: "direct main" description: name: video_compress - url: "https://pub.dartlang.org" + sha256: "407693726e674a1e1958801deb2d9daf5a5297707ba6d03375007012dae7389a" + url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" video_player: dependency: "direct main" description: name: video_player - url: "https://pub.dartlang.org" + sha256: "7bfb0f889879beb2980550a4df07721e980b59a874fc2c1019a6f85eab44bb95" + url: "https://pub.dev" source: hosted - version: "2.4.7" + version: "2.4.8" video_player_android: dependency: transitive description: name: video_player_android - url: "https://pub.dartlang.org" + sha256: d4d7313d1dc6f14d3414b98e2b268c3f34f4ac4ce4af51cf905e9a438edf0c77 + url: "https://pub.dev" source: hosted version: "2.3.9" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - url: "https://pub.dartlang.org" + sha256: "3df559495634bba8feb24439ac0a28a380d4ff96be7990811dc4ec81299e8cfa" + url: "https://pub.dev" source: hosted version: "2.3.7" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - url: "https://pub.dartlang.org" + sha256: "318a6d20577e1c78cf0bf40670883cc571ea860c72a4f7426d7dacce4bdd4343" + url: "https://pub.dev" source: hosted version: "5.1.4" video_player_web: dependency: transitive description: name: video_player_web - url: "https://pub.dartlang.org" + sha256: ed949a3df5fe88533254bbdd242c3d8eea19ecbc4e7af90da84ef087533f584b + url: "https://pub.dev" source: hosted version: "2.0.12" video_player_web_hls: dependency: "direct main" description: name: video_player_web_hls - url: "https://pub.dartlang.org" + sha256: d63442f2ec975134436b707725c6ce8cd9488245533c75663596bca1e993c8e2 + url: "https://pub.dev" source: hosted version: "0.1.11+6" video_thumbnail: dependency: "direct main" description: name: video_thumbnail - url: "https://pub.dartlang.org" + sha256: "3455c189d3f0bb4e3fc2236475aa84fe598b9b2d0e08f43b9761f5bc44210016" + url: "https://pub.dev" source: hosted version: "0.5.3" visibility_detector: dependency: transitive description: name: visibility_detector - url: "https://pub.dartlang.org" + sha256: "15c54a459ec2c17b4705450483f3d5a2858e733aee893dcee9d75fd04814940d" + url: "https://pub.dev" source: hosted version: "0.3.3" wakelock: dependency: transitive description: name: wakelock - url: "https://pub.dartlang.org" + sha256: "769ecf42eb2d07128407b50cb93d7c10bd2ee48f0276ef0119db1d25cc2f87db" + url: "https://pub.dev" source: hosted version: "0.6.2" wakelock_macos: dependency: transitive description: name: wakelock_macos - url: "https://pub.dartlang.org" + sha256: "047c6be2f88cb6b76d02553bca5a3a3b95323b15d30867eca53a19a0a319d4cd" + url: "https://pub.dev" source: hosted version: "0.4.0" wakelock_platform_interface: dependency: transitive description: name: wakelock_platform_interface - url: "https://pub.dartlang.org" + sha256: "1f4aeb81fb592b863da83d2d0f7b8196067451e4df91046c26b54a403f9de621" + url: "https://pub.dev" source: hosted version: "0.3.0" wakelock_web: dependency: transitive description: name: wakelock_web - url: "https://pub.dartlang.org" + sha256: "1b256b811ee3f0834888efddfe03da8d18d0819317f20f6193e2922b41a501b5" + url: "https://pub.dev" source: hosted version: "0.4.0" wakelock_windows: dependency: transitive description: name: wakelock_windows - url: "https://pub.dartlang.org" + sha256: "857f77b3fe6ae82dd045455baa626bc4b93cb9bb6c86bf3f27c182167c3a5567" + url: "https://pub.dev" source: hosted version: "0.2.1" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + url: "https://pub.dev" source: hosted version: "1.0.2" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd" + url: "https://pub.dev" source: hosted version: "2.2.0" webview_flutter: dependency: "direct main" description: name: webview_flutter - url: "https://pub.dartlang.org" + sha256: "392c1d83b70fe2495de3ea2c84531268d5b8de2de3f01086a53334d8b6030a88" + url: "https://pub.dev" source: hosted version: "3.0.4" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - url: "https://pub.dartlang.org" + sha256: "8b3b2450e98876c70bfcead876d9390573b34b9418c19e28168b74f6cb252dbd" + url: "https://pub.dev" source: hosted version: "2.10.4" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - url: "https://pub.dartlang.org" + sha256: "812165e4e34ca677bdfbfa58c01e33b27fd03ab5fa75b70832d4b7d4ca1fa8cf" + url: "https://pub.dev" source: hosted version: "1.9.5" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - url: "https://pub.dartlang.org" + sha256: a5364369c758892aa487cbf59ea41d9edd10f9d9baf06a94e80f1bd1b4c7bbc0 + url: "https://pub.dev" source: hosted version: "2.9.5" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + sha256: d13ac5deea7327f027b3b97ee19ee210f68256ecf3f1a304bcfb992ee947637c + url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.1.1" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + sha256: "11541eedefbcaec9de35aa82650b695297ce668662bbd6e3911a7fabdbde589f" + url: "https://pub.dev" source: hosted version: "0.2.0+2" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" + url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.2.2" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + url: "https://pub.dev" source: hosted version: "3.1.1" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=2.18.0 <4.0.0" flutter: ">=3.1.0-0" diff --git a/pubspec.yaml b/pubspec.yaml index 24e40e7c..5c2c55e9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.3+41 +version: 1.0.3+44 environment: sdk: ">=2.15.1 <3.0.0" @@ -97,6 +97,7 @@ flutter: assets: - assets/branding/three_speak_logo.png - assets/branding/three_speak_icon.png + - assets/branding/three_shorts_icon.png - .env # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg From 68d2e0bc2f9d2d717ab8e21aedb3d63106c0f15c Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 30 Nov 2022 15:37:50 +0530 Subject: [PATCH 136/466] supporting RPC change --- .DS_Store | Bin 8196 -> 8196 bytes .flutter-plugins-dependencies | 2 +- ios/Runner.xcodeproj/project.pbxproj | 12 +- ios/Runner/Info.plist | 2 +- lib/main.dart | 3 + .../models/user_stream/hive_user_stream.dart | 2 + .../communities_screen.dart | 35 +++-- .../community_details_screen.dart | 115 ++++++++------ lib/src/screens/home_screen/home_screen.dart | 145 ++++++++++-------- lib/src/screens/login/login_screen.dart | 16 +- .../account_settings_screen.dart | 2 + .../screens/my_account/my_account_screen.dart | 2 + .../update_video/video_details_info.dart | 5 +- lib/src/screens/search/search_screen.dart | 24 +-- lib/src/screens/settings/settings_screen.dart | 68 +++++++- lib/src/screens/stories/stories_feed.dart | 19 +-- lib/src/screens/stories/stories_screen.dart | 42 ++--- .../follower_list_tile.dart | 98 ++++++------ .../user_channel_following.dart | 14 +- .../user_channel_profile.dart | 14 +- .../user_channel_screen.dart | 6 +- .../user_channel_videos.dart | 14 +- .../video_details_comments.dart | 13 +- .../video_details_screen.dart | 56 ++++--- .../video_details_view_model.dart | 23 ++- lib/src/utils/communicator.dart | 33 ++-- lib/src/widgets/list_tile_video.dart | 21 +-- 27 files changed, 483 insertions(+), 303 deletions(-) diff --git a/.DS_Store b/.DS_Store index 2b91ba73e8727762e6010cffe22a8a8d5e377715..f1c0b6d6ac0610459711daa410763ce1c242534b 100644 GIT binary patch delta 50 zcmZp1XmQwZMR@W_!3tqZGaUsJW7Aq4g=#|+BMTh`GxNzILMEFhh?FpIW|#QJviX+? GJ2L>H0}ssr delta 73 zcmZp1XmQwZMVN8NWCzhgb&2X~6H7}S1ruZQS{;RIOCtjy+tR4EmXkwNS>HM+K07Bj cFTZPYfrva~_vQ&A<;CFBundleSignature ???? CFBundleVersion - 42 + 43 LSRequiresIPhoneOS LSSupportsOpeningDocumentsInPlace diff --git a/lib/main.dart b/lib/main.dart index b402eb68..78aab819 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -71,6 +71,7 @@ class _MyAppState extends State { cookie: null, postingKey: null, username: null, + rpc: 'api.hive.blog', ), child: StreamProvider.value( value: server.theme, @@ -138,12 +139,14 @@ class _MyAppState extends State { String? postingKey = await storage.read(key: 'postingKey'); String? cookie = await storage.read(key: 'cookie'); String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( HiveUserData( username: username, postingKey: postingKey, cookie: cookie, resolution: resolution, + rpc: rpc, ), ); } diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index 88a2542a..55745dac 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -3,11 +3,13 @@ class HiveUserData { String? postingKey; String? cookie; String resolution; + String rpc; HiveUserData({ required this.username, required this.postingKey, required this.cookie, required this.resolution, + required this.rpc, }); } diff --git a/lib/src/screens/communities_screen/communities_screen.dart b/lib/src/screens/communities_screen/communities_screen.dart index e50dd14b..f619f8e3 100644 --- a/lib/src/screens/communities_screen/communities_screen.dart +++ b/lib/src/screens/communities_screen/communities_screen.dart @@ -1,5 +1,6 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/communities_models/response/communities_response_models.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/communities_screen/community_details/community_details_screen.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; @@ -7,6 +8,7 @@ import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/retry.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; class CommunitiesScreen extends StatefulWidget { const CommunitiesScreen({ @@ -20,13 +22,7 @@ class CommunitiesScreen extends StatefulWidget { } class _CommunitiesScreenState extends State { - late Future> _future; - - @override - void initState() { - super.initState(); - _future = getListOfCommunities(); - } + Future>? _future; TextEditingController searchController = TextEditingController(); Widget _listTile(CommunityItem item) { @@ -80,7 +76,7 @@ class _CommunitiesScreenState extends State { child: const Text('Search'), onPressed: () { setState(() { - _future = getListOfCommunities(); + _future = null; }); }, ), @@ -93,19 +89,22 @@ class _CommunitiesScreenState extends State { ); } - Future> getListOfCommunities() { + Future> getListOfCommunities(String hiveApiUrl) { var value = searchController.value.text; - return Communicator().getListOfCommunities(value.isEmpty ? null : value); + return Communicator() + .getListOfCommunities(value.isEmpty ? null : value, hiveApiUrl); } - Widget _body() { + Widget _body(HiveUserData appData) { return FutureBuilder>( builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasError) { return RetryScreen( error: snapshot.error?.toString() ?? "Something went wrong", - onRetry: getListOfCommunities, + onRetry: () { + getListOfCommunities(appData.rpc); + }, ); } else if (snapshot.hasData) { return Container( @@ -115,7 +114,9 @@ class _CommunitiesScreenState extends State { } else { return RetryScreen( error: "Something went wrong", - onRetry: getListOfCommunities, + onRetry: () { + getListOfCommunities(appData.rpc); + }, ); } } else { @@ -131,11 +132,17 @@ class _CommunitiesScreenState extends State { @override Widget build(BuildContext context) { + var appData = Provider.of(context); + if (_future == null) { + setState(() { + _future = getListOfCommunities(appData.rpc); + }); + } return Scaffold( appBar: AppBar( title: const Text("Communities"), ), - body: _body(), + body: _body(appData), ); } } diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index 790e7877..aa2086eb 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -1,15 +1,13 @@ import 'dart:async'; -import 'dart:convert'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/communities_models/request/community_details_request.dart'; import 'package:acela/src/models/communities_models/response/community_details_response_models.dart'; -import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; @@ -19,6 +17,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:http/http.dart'; import 'package:http/http.dart' as http; +import 'package:provider/provider.dart'; import 'package:timeago/timeago.dart' as timeago; import 'package:url_launcher/url_launcher.dart'; @@ -43,12 +42,12 @@ class _CommunityDetailScreenState extends State Tab(text: 'Team') ]; - late Future> _loadingFeed; - late Future _details; + Future>? _loadingFeed; + Future? _details; Future> _loadHomeFeed() async { var uri = - Uri.parse('https://3speak.tv/apiv2/feeds/community/${widget.name}/new'); + Uri.parse('${server.domain}/apiv2/feeds/community/${widget.name}/new'); var response = await get(uri); if (response.statusCode == 200) { List list = homeFeedItemFromString(response.body); @@ -58,11 +57,11 @@ class _CommunityDetailScreenState extends State } } - Future _loadDetails() async { + Future _loadDetails(String hiveApiUrl) async { var client = http.Client(); var body = CommunityDetailsRequest.forName(widget.name).toJsonString(); var response = - await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); + await client.post(Uri.parse('https://$hiveApiUrl'), body: body); if (response.statusCode == 200) { return CommunityDetailsResponse.fromString(response.body); } else { @@ -73,8 +72,6 @@ class _CommunityDetailScreenState extends State @override void initState() { super.initState(); - _loadingFeed = _loadHomeFeed(); - _details = _loadDetails(); _tabController = TabController(length: tabs.length, vsync: this); } @@ -102,9 +99,9 @@ class _CommunityDetailScreenState extends State item.createdAt != null ? "📆 ${timeago.format(item.createdAt!)}" : ""; String duration = "🕚 ${Utilities.formatTime(item.duration.toInt())}"; String views = "▶ ${item.views}"; - double? payoutAmount = payout["${item.author}/${item.permlink}"]?.payout; - int? upVotes = payout["${item.author}/${item.permlink}"]?.upVotes; - int? downVotes = payout["${item.author}/${item.permlink}"]?.downVotes; + // double? payoutAmount = payout["${item.author}/${item.permlink}"]?.payout; + // int? upVotes = payout["${item.author}/${item.permlink}"]?.upVotes; + // int? downVotes = payout["${item.author}/${item.permlink}"]?.downVotes; return ListTileVideo( placeholder: 'assets/branding/three_speak_logo.png', url: item.images.thumbnail, @@ -120,35 +117,35 @@ class _CommunityDetailScreenState extends State ); } - void fetchHiveInfo(String user, String permlink) async { - var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); - request.body = json.encode({ - "id": 1, - "jsonrpc": "2.0", - "method": "bridge.get_discussion", - "params": {"author": user, "permlink": permlink, "observer": ""} - }); - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - var string = await response.stream.bytesToString(); - var result = HivePostInfo.fromJsonString(string) - .result - .resultData - .where((element) => element.permlink == permlink) - .first; - setState(() { - var upVotes = result.activeVotes.where((e) => e.rshares > 0).length; - var downVotes = result.activeVotes.where((e) => e.rshares < 0).length; - payout["$user/$permlink"] = PayoutInfo( - payout: result.payout, - downVotes: downVotes, - upVotes: upVotes, - ); - }); - } else { - print(response.reasonPhrase); - } - } + // void fetchHiveInfo(String user, String permlink) async { + // var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); + // request.body = json.encode({ + // "id": 1, + // "jsonrpc": "2.0", + // "method": "bridge.get_discussion", + // "params": {"author": user, "permlink": permlink, "observer": ""} + // }); + // http.StreamedResponse response = await request.send(); + // if (response.statusCode == 200) { + // var string = await response.stream.bytesToString(); + // var result = HivePostInfo.fromJsonString(string) + // .result + // .resultData + // .where((element) => element.permlink == permlink) + // .first; + // setState(() { + // var upVotes = result.activeVotes.where((e) => e.rshares > 0).length; + // var downVotes = result.activeVotes.where((e) => e.rshares < 0).length; + // payout["$user/$permlink"] = PayoutInfo( + // payout: result.payout, + // downVotes: downVotes, + // upVotes: upVotes, + // ); + // }); + // } else { + // print(response.reasonPhrase); + // } + // } Widget _listTile(HomeFeedItem item, BuildContext context, Function(HomeFeedItem) onTap, Function(HomeFeedItem) onUserTap) { @@ -212,14 +209,18 @@ class _CommunityDetailScreenState extends State ); } - Widget _about() { + Widget _about(HiveUserData appData) { return FutureBuilder( future: _details, builder: (builder, snapshot) { if (snapshot.hasError) { return RetryScreen( error: snapshot.error?.toString() ?? 'Something went wrong', - onRetry: _loadDetails); + onRetry: () { + setState(() { + _details = null; + }); + }); } else if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) { CommunityDetailsResponse data = @@ -235,14 +236,19 @@ class _CommunityDetailScreenState extends State ); } - Widget _team() { + Widget _team(HiveUserData appData) { return FutureBuilder( future: _details, builder: (builder, snapshot) { if (snapshot.hasError) { return RetryScreen( - error: snapshot.error?.toString() ?? 'Something went wrong', - onRetry: _loadDetails); + error: snapshot.error?.toString() ?? 'Something went wrong', + onRetry: () { + setState(() { + _details = null; + }); + }, + ); } else if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) { CommunityDetailsResponse data = @@ -274,6 +280,17 @@ class _CommunityDetailScreenState extends State @override Widget build(BuildContext context) { + var appData = Provider.of(context); + if (_loadingFeed == null) { + setState(() { + _loadingFeed = _loadHomeFeed(); + }); + } + if (_details == null) { + setState(() { + _details = _loadDetails(appData.rpc); + }); + } return Scaffold( appBar: AppBar( title: Row( @@ -297,8 +314,8 @@ class _CommunityDetailScreenState extends State controller: _tabController, children: [ _screen(), - _about(), - _team(), + _about(appData), + _team(appData), ], ), ); diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 9a431877..2365cb69 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; @@ -8,19 +10,20 @@ import 'package:acela/src/screens/upload/new_video_upload_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; -import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:acela/src/widgets/retry.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' show get; import 'package:provider/provider.dart'; class HomeScreen extends StatefulWidget { - const HomeScreen( - {Key? key, - required this.path, - required this.showDrawer, - required this.title}) - : super(key: key); + const HomeScreen({ + Key? key, + required this.path, + required this.showDrawer, + required this.title, + }) : super(key: key); final String path; final bool showDrawer; final String title; @@ -63,47 +66,23 @@ class HomeScreen extends StatefulWidget { class _HomeScreenState extends State { final widgets = HomeScreenWidgets(); - List items = []; - var isLoading = false; - Map payout = {}; - var isFabLoading = false; + Future>? _future; @override void initState() { super.initState(); - loadData(); + if (_future == null) { + updateFeed(); + } } - void loadData() async { - setState(() { - isLoading = true; - }); + Future> _loadFeed() async { var response = await get(Uri.parse(widget.path)); if (response.statusCode == 200) { List list = homeFeedItemFromString(response.body); - setState(() { - isLoading = false; - items = list; - }); - var i = 0; - while (i < list.length) { - if (mounted) { - var info = await Communicator() - .fetchHiveInfo(list[i].author, list[i].permlink); - setState(() { - payout["${list[i].author}/${list[i].permlink}"] = info; - i++; - }); - } else { - break; - } - } + return list; } else { - showError('Status code ${response.statusCode}'); - setState(() { - isLoading = false; - items = []; - }); + throw 'Status code ${response.statusCode}'; } } @@ -131,15 +110,41 @@ class _HomeScreenState extends State { ScaffoldMessenger.of(context).showSnackBar(snackBar); } - Widget _screen() { - if (isLoading) { - return widgets.loadingData(); - } - return widgets.list(items, (item) { - onTap(item); - }, (item) { - onUserTap(item); - }, payout); + Widget _screen(HiveUserData appData) { + return FutureBuilder>( + builder: (c, s) { + if (s.connectionState == ConnectionState.done) { + if (s.hasError) { + return RetryScreen( + error: s.error?.toString() ?? "Something went wrong", + onRetry: () { + _future = null; + }, + ); + } else if (s.hasData) { + var list = s.data as List; + return widgets.list(list, (item) { + onTap(item); + }, (item) { + onUserTap(item); + }, {}); + } else { + return RetryScreen( + error: "Something went wrong", + onRetry: () { + _future = null; + }, + ); + } + } else { + return const LoadingScreen( + title: 'Loading Data', + subtitle: 'Please wait', + ); + } + }, + future: _future, + ); } void showBottomSheetForVideoOptions(bool isReel) { @@ -215,26 +220,36 @@ class _HomeScreenState extends State { ); } + void updateFeed() { + Timer.periodic(const Duration(milliseconds: 1000), (timer) { + timer.cancel(); + setState(() { + _future = _loadFeed(); + }); + }); + } + @override Widget build(BuildContext context) { - var user = Provider.of(context); + var appData = Provider.of(context); return Scaffold( - appBar: AppBar( - title: Text(widget.title), - actions: [ - IconButton( - onPressed: () { - var route = MaterialPageRoute( - builder: (context) => const SearchScreen()); - Navigator.of(context).push(route); - }, - icon: const Icon(Icons.search)) - ], - ), - body: _screen(), - drawer: widget.showDrawer ? const DrawerScreen() : null, - floatingActionButton: - user.username == null ? null : _fabNewUpload() //_fab(user), - ); + appBar: AppBar( + title: Text(widget.title), + actions: [ + IconButton( + onPressed: () { + var route = MaterialPageRoute( + builder: (context) => const SearchScreen(), + ); + Navigator.of(context).push(route); + }, + icon: const Icon(Icons.search), + ) + ], + ), + body: _screen(appData), + drawer: widget.showDrawer ? const DrawerScreen() : null, + floatingActionButton: appData.username == null ? null : _fabNewUpload(), + ); } } diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 71f866e2..ffc628da 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -5,6 +5,7 @@ import 'package:acela/src/utils/crypto_manager.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:provider/provider.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({Key? key}) : super(key: key); @@ -22,17 +23,18 @@ class _LoginScreenState extends State { // Create storage static const storage = FlutterSecureStorage(); - void onLoginTapped() async { + void onLoginTapped(HiveUserData appData) async { setState(() { isLoading = true; }); try { - var publicKey = await Communicator().getPublicKey(username); + var publicKey = await Communicator().getPublicKey(username, appData.rpc); var resultingKey = CryptoManager().privToPub(postingKey); if (resultingKey == publicKey) { // it is valid key debugPrint("Successful login"); String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; await storage.write(key: 'username', value: username); await storage.write(key: 'postingKey', value: postingKey); await storage.delete(key: 'cookie'); @@ -42,6 +44,7 @@ class _LoginScreenState extends State { postingKey: postingKey, cookie: null, resolution: resolution, + rpc: rpc, ), ); Navigator.of(context).pop(); @@ -68,7 +71,7 @@ class _LoginScreenState extends State { ScaffoldMessenger.of(context).showSnackBar(snackBar); } - Widget _loginForm() { + Widget _loginForm(HiveUserData appData) { return Container( margin: EdgeInsets.all(10), child: Column( @@ -106,7 +109,9 @@ class _LoginScreenState extends State { isLoading ? CircularProgressIndicator() : ElevatedButton( - onPressed: onLoginTapped, + onPressed: () { + onLoginTapped(appData); + }, child: const Text('Log in'), ), ], @@ -121,6 +126,7 @@ class _LoginScreenState extends State { @override Widget build(BuildContext context) { + var data = Provider.of(context); return Scaffold( appBar: AppBar( title: const Text('Login'), @@ -134,7 +140,7 @@ class _LoginScreenState extends State { ) ], ), - body: _loginForm(), + body: _loginForm(data), ); } } diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index 587fa7e8..c37a3657 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -18,12 +18,14 @@ class _AccountSettingsScreenState extends State { await storage.delete(key: 'postingKey'); await storage.delete(key: 'cookie'); String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( HiveUserData( username: null, postingKey: null, cookie: null, resolution: resolution, + rpc: rpc, ), ); Navigator.of(context).pop(); diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 8808216e..a060bd9d 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -29,12 +29,14 @@ class _MyAccountScreenState extends State { await storage.delete(key: 'postingKey'); await storage.delete(key: 'cookie'); String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( HiveUserData( username: null, postingKey: null, cookie: null, resolution: resolution, + rpc: rpc, ), ); Navigator.of(context).pop(); diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index 02516317..54c917a2 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -104,7 +104,8 @@ class _VideoDetailsInfoState extends State { }); try { var doesPostNotExist = await Communicator() - .doesPostNotExist(widget.item.owner, widget.item.permlink); + .doesPostNotExist(widget.item.owner, widget.item.permlink, user.rpc); + await Future.delayed(const Duration(seconds: 1), () {}); if (doesPostNotExist != true) { await Communicator().updatePublishState(user, widget.item.id); setState(() { @@ -123,6 +124,7 @@ class _VideoDetailsInfoState extends State { tags: tags, thumbnail: thumbIpfs.isEmpty ? null : thumbIpfs, ); + await Future.delayed(const Duration(seconds: 1), () {}); const platform = MethodChannel('com.example.acela/auth'); var title = base64.encode(utf8.encode(widget.title)); var description = base64.encode(utf8.encode(widget.subtitle)); @@ -146,6 +148,7 @@ class _VideoDetailsInfoState extends State { log('Response from platform $response'); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); if (bridgeResponse.error == "success") { + await Future.delayed(const Duration(seconds: 3), () {}); await Communicator().updatePublishState(user, v.id); setState(() { isCompleting = false; diff --git a/lib/src/screens/search/search_screen.dart b/lib/src/screens/search/search_screen.dart index b54433ae..cce8cc5c 100644 --- a/lib/src/screens/search/search_screen.dart +++ b/lib/src/screens/search/search_screen.dart @@ -6,14 +6,15 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/search/search_response_models.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:http/http.dart' as http; +import 'package:provider/provider.dart'; import 'package:timeago/timeago.dart' as timeago; class SearchScreen extends StatefulWidget { @@ -31,7 +32,7 @@ class _SearchScreenState extends State { var loading = false; Map payout = {}; - Future search(String term) async { + Future search(String term, HiveUserData appData) async { var headers = { 'Content-Type': 'application/json', 'Authorization': dotenv.env['HIVE_SEARCHER_AUTH_KEY'] ?? '' @@ -56,7 +57,7 @@ class _SearchScreenState extends State { }); var i = 0; Timer.periodic(const Duration(seconds: 1), (timer) { - fetchHiveInfo(results[i].author, results[i].permlink); + fetchHiveInfo(results[i].author, results[i].permlink, appData.rpc); i += 1; if (i == results.length) { timer.cancel(); @@ -71,8 +72,8 @@ class _SearchScreenState extends State { } // fetch hive info - void fetchHiveInfo(String user, String permlink) async { - var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); + void fetchHiveInfo(String user, String permlink, String hiveApiUrl) async { + var request = http.Request('POST', Uri.parse('https://$hiveApiUrl')); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", @@ -113,7 +114,7 @@ class _SearchScreenState extends State { super.dispose(); } - PreferredSizeWidget _appBar() { + PreferredSizeWidget _appBar(HiveUserData appData) { return AppBar( title: TextField( controller: _controller, @@ -121,7 +122,7 @@ class _SearchScreenState extends State { var timer = Timer(const Duration(seconds: 2), () { log('Text changed to $value'); if (value.trim().length > 3) { - search(value.trim()); + search(value.trim(), appData); } }); setState(() { @@ -137,9 +138,9 @@ class _SearchScreenState extends State { var created = DateTime.tryParse(item.createdAt); String timeInString = created != null ? "📆 ${timeago.format(created)}" : ""; - double? payoutAmount = payout["${item.author}/${item.permlink}"]?.payout; - int? upVotes = payout["${item.author}/${item.permlink}"]?.upVotes; - int? downVotes = payout["${item.author}/${item.permlink}"]?.downVotes; + // double? payoutAmount = payout["${item.author}/${item.permlink}"]?.payout; + // int? upVotes = payout["${item.author}/${item.permlink}"]?.upVotes; + // int? downVotes = payout["${item.author}/${item.permlink}"]?.downVotes; return ListTile( contentPadding: EdgeInsets.zero, minVerticalPadding: 0, @@ -189,8 +190,9 @@ class _SearchScreenState extends State { @override Widget build(BuildContext context) { + var appData = Provider.of(context); return Scaffold( - appBar: _appBar(), + appBar: _appBar(appData), body: _searchResultListView(), ); } diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index 99c2a186..594af285 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -46,12 +46,14 @@ class _SettingsScreenState extends State { String? username = await storage.read(key: 'username'); String? postingKey = await storage.read(key: 'postingKey'); String? cookie = await storage.read(key: 'cookie'); + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( HiveUserData( username: username, postingKey: postingKey, cookie: cookie, resolution: optionName, + rpc: rpc, ), ); loadRes(); @@ -94,24 +96,86 @@ class _SettingsScreenState extends State { ); } - Widget _drawerMenu(BuildContext context) { + BottomSheetAction getActionForRpc(String serverUrl, HiveUserData user) { + return BottomSheetAction( + title: Text(serverUrl), + onPressed: (context) async { + Navigator.of(context).pop(); + const storage = FlutterSecureStorage(); + await storage.write(key: 'rpc', value: serverUrl); + server.updateHiveUserData( + HiveUserData( + username: user.username, + postingKey: user.postingKey, + cookie: user.cookie, + resolution: user.resolution, + rpc: serverUrl, + ), + ); + }, + ); + } + + void showBottomSheetForServer(HiveUserData user) { + var list = [ + 'api.hive.blog', + 'api.deathwing.me', + 'hive-api.arcange.eu', + 'hived.emre.sh', + 'api.openhive.network', + 'rpc.ausbit.dev', + 'anyx.io', + 'techcoderx.com', + 'api.hive.blue', + 'api.pharesim.me', + 'hived.privex.io', + 'hive.roelandp.nl', + ].map((e) => getActionForRpc(e, user)).toList(); + showAdaptiveActionSheet( + context: context, + title: const Text('Select Hive API Node (RPC)'), + androidBorderRadius: 30, + actions: list, + cancelAction: CancelAction( + title: const Text( + 'Cancel', + style: TextStyle(color: Colors.deepOrange), + ), + ), + ); + } + + Widget _rpc(BuildContext context, HiveUserData user) { + return ListTile( + leading: const Icon(Icons.cloud), + title: const Text("Change Hive API Node (RPC)"), + subtitle: Text(user.rpc), + onTap: () { + showBottomSheetForServer(user); + }, + ); + } + + Widget _drawerMenu(BuildContext context, HiveUserData user) { return ListView( children: [ _changeTheme(context), _divider(), _video(context), _divider(), + _rpc(context, user) ], ); } @override Widget build(BuildContext context) { + var user = Provider.of(context); return Scaffold( appBar: AppBar( title: const Text('Settings'), ), - body: _drawerMenu(context), + body: _drawerMenu(context, user), ); } } diff --git a/lib/src/screens/stories/stories_feed.dart b/lib/src/screens/stories/stories_feed.dart index c000a571..0e98e691 100644 --- a/lib/src/screens/stories/stories_feed.dart +++ b/lib/src/screens/stories/stories_feed.dart @@ -12,11 +12,10 @@ import 'package:http/http.dart'; import 'package:provider/provider.dart'; class StoriesFeedScreen extends StatefulWidget { - const StoriesFeedScreen({ - Key? key, - required this.type, - }) : super(key: key); + const StoriesFeedScreen({Key? key, required this.type, required this.height}) + : super(key: key); final String type; + final double height; @override State createState() => _StoriesFeedScreenState(); @@ -42,7 +41,7 @@ class _StoriesFeedScreenState extends State { List list = homeFeedItemFromString(response.body); setState(() { isLoading = false; - items = list.where((element) => element.duration < 300).toList(); + items = list.where((element) => element.duration < 180).toList(); }); } else { showError('Status code ${response.statusCode}'); @@ -78,7 +77,7 @@ class _StoriesFeedScreenState extends State { playUrl: item.getVideoUrl(data), thumbnail: item.images.thumbnail, width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, + height: MediaQuery.of(context).size.height - widget.height, ), Container( child: Row( @@ -98,14 +97,16 @@ class _StoriesFeedScreenState extends State { playUrl: item.getVideoUrl(data), thumbnail: item.images.thumbnail, width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, + height: MediaQuery.of(context).size.height - widget.height, ), Container( child: Row( children: [ const Spacer(), - Text('@${item.author}/${item.permlink}', - style: Theme.of(context).textTheme.titleLarge), + Text( + '@${item.author}/${item.permlink}', + style: Theme.of(context).textTheme.titleLarge, + ), const Spacer(), ], ), diff --git a/lib/src/screens/stories/stories_screen.dart b/lib/src/screens/stories/stories_screen.dart index e8d2b7f3..c1362ca8 100644 --- a/lib/src/screens/stories/stories_screen.dart +++ b/lib/src/screens/stories/stories_screen.dart @@ -30,29 +30,31 @@ class _StoriesScreenState extends State { length: tabs.length, child: Builder( builder: (context) { - return Scaffold( - appBar: AppBar( - centerTitle: true, - title: Row( - children: [ - Image.asset( - "assets/branding/three_shorts_icon.png", - width: 40, - height: 40, - ), - const SizedBox(width: 15), - const Text('3Shorts') - ], - ), - bottom: TabBar( - tabs: tabs, - ), + var appBar = AppBar( + centerTitle: true, + title: Row( + children: [ + Image.asset( + "assets/branding/three_shorts_icon.png", + width: 40, + height: 40, + ), + const SizedBox(width: 15), + const Text('3Shorts') + ], ), + bottom: TabBar( + tabs: tabs, + ), + ); + var height = appBar.preferredSize.height; + return Scaffold( + appBar: appBar, body: TabBarView( children: [ - StoriesFeedScreen(type: 'trending'), - StoriesFeedScreen(type: 'new'), - StoriesFeedScreen(type: 'firstUploads'), + StoriesFeedScreen(type: 'trending', height: height), + StoriesFeedScreen(type: 'new', height: height), + StoriesFeedScreen(type: 'firstUploads', height: height), ], ), ); diff --git a/lib/src/screens/user_channel_screen/follower_list_tile.dart b/lib/src/screens/user_channel_screen/follower_list_tile.dart index 3ddeeca7..52fff588 100644 --- a/lib/src/screens/user_channel_screen/follower_list_tile.dart +++ b/lib/src/screens/user_channel_screen/follower_list_tile.dart @@ -1,12 +1,8 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/user_profile/request/user_profile_request.dart'; -import 'package:acela/src/models/user_profile/response/user_profile.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; class FollowerListTile extends StatefulWidget { const FollowerListTile({Key? key, required this.name}) : super(key: key); @@ -21,54 +17,54 @@ class _FollowerListTileState extends State @override bool get wantKeepAlive => true; - Future _loadUserProfile() async { - var client = http.Client(); - var body = UserProfileRequest.forOwner(widget.name).toJsonString(); - var response = - await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); - if (response.statusCode == 200) { - return UserProfileResponse.fromString(response.body); - } else { - throw "Status code is ${response.statusCode}"; - } - } + // Future _loadUserProfile(String hiveApiUrl) async { + // var client = http.Client(); + // var body = UserProfileRequest.forOwner(widget.name).toJsonString(); + // var response = + // await client.post(Uri.parse('https://$hiveApiUrl'), body: body); + // if (response.statusCode == 200) { + // return UserProfileResponse.fromString(response.body); + // } else { + // throw "Status code is ${response.statusCode}"; + // } + // } - Widget _futureUserProfile() { - return FutureBuilder( - future: _loadUserProfile(), - builder: (context, snapshot) { - if (snapshot.hasError) { - return ListTile(title: Text(widget.name)); - } else if (snapshot.hasData && - snapshot.connectionState == ConnectionState.done) { - var data = snapshot.data! as UserProfileResponse; - return ListTile( - leading: SizedBox( - height: 40, - width: 40, - child: FadeInImage.assetNetwork( - placeholder: 'assets/branding/three_speak_logo.png', - image: data.result.metadata.profile.profileImage, - fit: BoxFit.cover, - placeholderErrorBuilder: (BuildContext context, Object error, - StackTrace? stackTrace) { - return Image.asset('assets/branding/three_speak_logo.png'); - }, - imageErrorBuilder: (BuildContext context, Object error, - StackTrace? stackTrace) { - return Image.asset('assets/branding/three_speak_logo.png'); - }, - ), - ), - title: Text(widget.name), - subtitle: Text('Reputation: ${data.result.reputation}'), - ); - } else { - return ListTile(title: Text(widget.name)); - } - }, - ); - } + // Widget _futureUserProfile(HiveUserData appData) { + // return FutureBuilder( + // future: _loadUserProfile(appData.rpc), + // builder: (context, snapshot) { + // if (snapshot.hasError) { + // return ListTile(title: Text(widget.name)); + // } else if (snapshot.hasData && + // snapshot.connectionState == ConnectionState.done) { + // var data = snapshot.data! as UserProfileResponse; + // return ListTile( + // leading: SizedBox( + // height: 40, + // width: 40, + // child: FadeInImage.assetNetwork( + // placeholder: 'assets/branding/three_speak_logo.png', + // image: data.result.metadata.profile.profileImage, + // fit: BoxFit.cover, + // placeholderErrorBuilder: (BuildContext context, Object error, + // StackTrace? stackTrace) { + // return Image.asset('assets/branding/three_speak_logo.png'); + // }, + // imageErrorBuilder: (BuildContext context, Object error, + // StackTrace? stackTrace) { + // return Image.asset('assets/branding/three_speak_logo.png'); + // }, + // ), + // ), + // title: Text(widget.name), + // subtitle: Text('Reputation: ${data.result.reputation}'), + // ); + // } else { + // return ListTile(title: Text(widget.name)); + // } + // }, + // ); + // } @override Widget build(BuildContext context) { diff --git a/lib/src/screens/user_channel_screen/user_channel_following.dart b/lib/src/screens/user_channel_screen/user_channel_following.dart index fed3af34..a626cd02 100644 --- a/lib/src/screens/user_channel_screen/user_channel_following.dart +++ b/lib/src/screens/user_channel_screen/user_channel_following.dart @@ -1,10 +1,11 @@ import 'package:acela/src/models/user_profile/request/user_followers_request.dart'; import 'package:acela/src/models/user_profile/response/followers_and_following.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/user_channel_screen/follower_list_tile.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; +import 'package:provider/provider.dart'; class UserChannelFollowingWidget extends StatefulWidget { const UserChannelFollowingWidget( @@ -23,13 +24,13 @@ class _UserChannelFollowingWidgetState extends State @override bool get wantKeepAlive => true; - Future _loadFollowers(String author) async { + Future _loadFollowers(String author, String hiveApiUrl) async { var client = http.Client(); var body = widget.isFollowers ? UserFollowerRequest.followers(widget.owner).toJsonString() : UserFollowerRequest.following(widget.owner).toJsonString(); var response = - await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); + await client.post(Uri.parse('https://$hiveApiUrl'), body: body); if (response.statusCode == 200) { return Followers.fromJsonString(response.body); } else { @@ -43,9 +44,9 @@ class _UserChannelFollowingWidgetState extends State ); } - Widget _futureFollowers() { + Widget _futureFollowers(HiveUserData appData) { return FutureBuilder( - future: _loadFollowers(widget.owner), + future: _loadFollowers(widget.owner, appData.rpc), builder: (context, snapshot) { if (snapshot.hasError) { return const Text('Error loading user followers'); @@ -79,6 +80,7 @@ class _UserChannelFollowingWidgetState extends State @override Widget build(BuildContext context) { super.build(context); - return _futureFollowers(); + var appData = Provider.of(context); + return _futureFollowers(appData); } } diff --git a/lib/src/screens/user_channel_screen/user_channel_profile.dart b/lib/src/screens/user_channel_screen/user_channel_profile.dart index cb291ffd..10e462c4 100644 --- a/lib/src/screens/user_channel_screen/user_channel_profile.dart +++ b/lib/src/screens/user_channel_screen/user_channel_profile.dart @@ -1,11 +1,12 @@ import 'package:acela/src/models/user_profile/request/user_profile_request.dart'; import 'package:acela/src/models/user_profile/response/user_profile.dart'; -import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:http/http.dart' as http; +import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; class UserChannelProfileWidget extends StatefulWidget { @@ -23,11 +24,11 @@ class _UserChannelProfileWidgetState extends State @override bool get wantKeepAlive => true; - Future _loadUserProfile() async { + Future _loadUserProfile(String hiveApiUrl) async { var client = http.Client(); var body = UserProfileRequest.forOwner(widget.owner).toJsonString(); var response = - await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); + await client.post(Uri.parse('https://$hiveApiUrl'), body: body); if (response.statusCode == 200) { return UserProfileResponse.fromString(response.body); } else { @@ -62,9 +63,9 @@ class _UserChannelProfileWidgetState extends State return "![cover image](${data.result.metadata.profile.coverImage})\n## Bio:\n${data.result.metadata.profile.about}\n\n\n## Created At:\n${Utilities.parseAndFormatDateTime(data.result.created)}\n\n## Last Seen At:\n${Utilities.parseAndFormatDateTime(data.result.active)}\n\n## Total Hive Posts:\n${data.result.postCount}\n\n## Hive Reputation:\n${data.result.reputation}\n\n## Location:\n${data.result.metadata.profile.location.isEmpty ? 'None' : data.result.metadata.profile.location}\n\n## Website:\n${data.result.metadata.profile.website.isEmpty ? 'None' : data.result.metadata.profile.website}"; } - Widget _futureUserProfile() { + Widget _futureUserProfile(HiveUserData appData) { return FutureBuilder( - future: _loadUserProfile(), + future: _loadUserProfile(appData.rpc), builder: (context, snapshot) { if (snapshot.hasError) { return const Text('Error loading user profile'); @@ -85,6 +86,7 @@ class _UserChannelProfileWidgetState extends State @override Widget build(BuildContext context) { super.build(context); - return _futureUserProfile(); + var appData = Provider.of(context); + return _futureUserProfile(appData); } } diff --git a/lib/src/screens/user_channel_screen/user_channel_screen.dart b/lib/src/screens/user_channel_screen/user_channel_screen.dart index cece833f..ed580202 100644 --- a/lib/src/screens/user_channel_screen/user_channel_screen.dart +++ b/lib/src/screens/user_channel_screen/user_channel_screen.dart @@ -1,10 +1,12 @@ import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_following.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_profile.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_videos.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class UserChannelScreen extends StatefulWidget { const UserChannelScreen({Key? key, required this.owner}) : super(key: key); @@ -78,6 +80,7 @@ class _UserChannelScreenState extends State @override Widget build(BuildContext context) { + var appData = Provider.of(context); return Scaffold( appBar: AppBar( title: Row( @@ -103,7 +106,8 @@ class _UserChannelScreenState extends State body: TabBarView( controller: _tabController, children: [ - UserChannelVideos(key: videoKey, owner: widget.owner), + UserChannelVideos( + key: videoKey, owner: widget.owner, rpc: appData.rpc), UserChannelProfileWidget(owner: widget.owner), UserChannelFollowingWidget(owner: widget.owner, isFollowers: true), UserChannelFollowingWidget(owner: widget.owner, isFollowers: false), diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart index 9607dd35..e719a868 100644 --- a/lib/src/screens/user_channel_screen/user_channel_videos.dart +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -7,7 +7,6 @@ import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:acela/src/widgets/loading_screen.dart'; @@ -17,8 +16,13 @@ import 'package:http/http.dart' as http; import 'package:timeago/timeago.dart' as timeago; class UserChannelVideos extends StatefulWidget { - const UserChannelVideos({Key? key, required this.owner}) : super(key: key); + const UserChannelVideos({ + Key? key, + required this.owner, + required this.rpc, + }) : super(key: key); final String owner; + final String rpc; @override State createState() => UserChannelVideosState(); @@ -74,7 +78,7 @@ class UserChannelVideosState extends State }); var i = 0; Timer.periodic(const Duration(seconds: 1), (timer) { - fetchHiveInfo(list[i].author, list[i].permlink); + fetchHiveInfo(list[i].author, list[i].permlink, widget.rpc); i += 1; if (i == list.length) { timer.cancel(); @@ -90,8 +94,8 @@ class UserChannelVideosState extends State } // fetch hive info - void fetchHiveInfo(String user, String permlink) async { - var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); + void fetchHiveInfo(String user, String permlink, String hiveApiUrl) async { + var request = http.Request('POST', Uri.parse('https://$hiveApiUrl')); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart index c4269c76..088cac9b 100644 --- a/lib/src/screens/video_details_screen/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -1,16 +1,19 @@ import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/screens/video_details_screen/hive_comment.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; class VideoDetailsComments extends StatefulWidget { - const VideoDetailsComments( - {Key? key, required this.author, required this.permlink}) - : super(key: key); + const VideoDetailsComments({ + Key? key, + required this.author, + required this.permlink, + required this.rpc, + }) : super(key: key); final String author; final String permlink; + final String rpc; @override State createState() => _VideoDetailsCommentsState(); @@ -24,7 +27,7 @@ class _VideoDetailsCommentsState extends State { var body = hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); var response = - await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); + await client.post(Uri.parse('https://${widget.rpc}'), body: body); if (response.statusCode == 200) { var hiveCommentsResponse = hiveCommentsFromString(response.body); var comments = hiveCommentsResponse.result; diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 82232ed6..ec0f7f89 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -12,7 +12,6 @@ import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; import 'package:acela/src/screens/video_details_screen/video_details_info.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; @@ -36,17 +35,15 @@ class VideoDetailsScreen extends StatefulWidget { class _VideoDetailsScreenState extends State { late Future> recommendedVideos; - late Future> _loadComments; + Future>? _loadComments; - late Future _fetchHiveInfoForThisVideo; + Future? _fetchHiveInfoForThisVideo; @override void initState() { super.initState(); - _fetchHiveInfoForThisVideo = fetchHiveInfoForThisVideo(); + // _fetchHiveInfoForThisVideo = fetchHiveInfoForThisVideo(); recommendedVideos = widget.vm.getRecommendedVideos(); - _loadComments = - widget.vm.loadFirstSetOfComments(widget.vm.author, widget.vm.permlink); } void onUserTap() { @@ -76,8 +73,9 @@ class _VideoDetailsScreenState extends State { } // fetch hive info - Future fetchHiveInfoForThisVideo() async { - var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); + Future fetchHiveInfoForThisVideo( + String hiveApiUrl) async { + var request = http.Request('POST', Uri.parse('https://$hiveApiUrl')); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", @@ -254,7 +252,7 @@ class _VideoDetailsScreenState extends State { } // video comments - Widget commentsSection(List comments) { + Widget commentsSection(List comments, HiveUserData appData) { var filtered = comments.where((element) => (element.netRshares ?? 0) >= 0 && (element.authorReputation ?? 0) >= 0); if (filtered.isEmpty) { @@ -279,7 +277,10 @@ class _VideoDetailsScreenState extends State { MaterialPageRoute( builder: (context) { return VideoDetailsComments( - author: widget.vm.author, permlink: widget.vm.permlink); + author: widget.vm.author, + permlink: widget.vm.permlink, + rpc: appData.rpc, + ); }, ), ); @@ -288,7 +289,7 @@ class _VideoDetailsScreenState extends State { } // video comments - Widget videoComments() { + Widget videoComments(HiveUserData appData) { return FutureBuilder( future: _loadComments, builder: (builder, snapshot) { @@ -299,7 +300,7 @@ class _VideoDetailsScreenState extends State { } else if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) { var data = snapshot.data! as List; - return commentsSection(data); + return commentsSection(data, appData); } else { return Container( margin: const EdgeInsets.all(10), @@ -322,7 +323,10 @@ class _VideoDetailsScreenState extends State { //endregion - Widget videoWithDetailsWithoutRecommendation(VideoDetails details) { + Widget videoWithDetailsWithoutRecommendation( + VideoDetails details, + HiveUserData appData, + ) { return Container( margin: const EdgeInsets.only(top: 230), child: ListView.separated( @@ -330,7 +334,7 @@ class _VideoDetailsScreenState extends State { if (index == 0) { return titleAndSubtitle(details); } else if (index == 1) { - return videoComments(); + return videoComments(appData); } else { return ListTile( contentPadding: EdgeInsets.zero, @@ -347,12 +351,12 @@ class _VideoDetailsScreenState extends State { } // container list view - Widget videoWithDetails(VideoDetails details) { + Widget videoWithDetails(VideoDetails details, HiveUserData appData) { return FutureBuilder( future: recommendedVideos, builder: (builder, snapshot) { if (snapshot.hasError) { - return videoWithDetailsWithoutRecommendation(details); + return videoWithDetailsWithoutRecommendation(details, appData); } else if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) { var recommendations = @@ -364,7 +368,7 @@ class _VideoDetailsScreenState extends State { if (index == 0) { return titleAndSubtitle(details); } else if (index == 1) { - return videoComments(); + return videoComments(appData); } else if (index == 2) { return const ListTile( title: Text('Recommended Videos'), @@ -395,7 +399,7 @@ class _VideoDetailsScreenState extends State { ), ); } else { - return videoWithDetailsWithoutRecommendation(details); + return videoWithDetailsWithoutRecommendation(details, appData); } }); } @@ -422,6 +426,20 @@ class _VideoDetailsScreenState extends State { @override Widget build(BuildContext context) { var userData = Provider.of(context); + if (_loadComments == null) { + setState(() { + _loadComments = widget.vm.loadFirstSetOfComments( + widget.vm.author, + widget.vm.permlink, + userData.rpc, + ); + }); + } + if (_fetchHiveInfoForThisVideo == null) { + setState(() { + _fetchHiveInfoForThisVideo = fetchHiveInfoForThisVideo(userData.rpc); + }); + } return FutureBuilder( future: widget.vm.getVideoDetails(), builder: (builder, snapshot) { @@ -438,7 +456,7 @@ class _VideoDetailsScreenState extends State { body: SafeArea( child: Stack( children: [ - videoWithDetails(data), + videoWithDetails(data, userData), SizedBox( height: 230, child: Platform.isAndroid diff --git a/lib/src/screens/video_details_screen/video_details_view_model.dart b/lib/src/screens/video_details_screen/video_details_view_model.dart index f1460973..e4987751 100644 --- a/lib/src/screens/video_details_screen/video_details_view_model.dart +++ b/lib/src/screens/video_details_screen/video_details_view_model.dart @@ -3,7 +3,6 @@ import 'package:acela/src/models/hive_comments/request/hive_comment_request.dart import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:http/http.dart' show get; import 'package:http/http.dart' as http; @@ -35,12 +34,16 @@ class VideoDetailsViewModel { } } - Future> loadComments(String author, String permlink) async { + Future> loadComments( + String author, + String permlink, + String hiveApiUrl, + ) async { var client = http.Client(); var body = hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); var response = - await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); + await client.post(Uri.parse('https://$hiveApiUrl'), body: body); if (response.statusCode == 200) { var hiveCommentsResponse = hiveCommentsFromString(response.body); var comments = hiveCommentsResponse.result; @@ -49,8 +52,11 @@ class VideoDetailsViewModel { if (comments .where((e) => e.parentPermlink == comments[i].permlink) .isEmpty) { - var newComments = - await loadComments(comments[i].author, comments[i].permlink); + var newComments = await loadComments( + comments[i].author, + comments[i].permlink, + hiveApiUrl, + ); comments.insertAll(i + 1, newComments); } } @@ -62,12 +68,15 @@ class VideoDetailsViewModel { } Future> loadFirstSetOfComments( - String author, String permlink) async { + String author, + String permlink, + String hiveApiUrl, + ) async { var client = http.Client(); var body = hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); var response = - await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); + await client.post(Uri.parse('https://$hiveApiUrl'), body: body); if (response.statusCode == 200) { var hiveCommentsResponse = hiveCommentsFromString(response.body); var comments = hiveCommentsResponse.result; diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 8c847421..242b49cb 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -36,11 +36,15 @@ class Communicator { // static const tsServer = "http://192.168.1.8:13050"; // static const fsServer = "http://192.168.1.8:1080/files"; - static const hiveApiUrl = 'https://api.hive.blog/'; + // static const hiveApiUrl = 'api.hive.blog'; static const threeSpeakCDN = 'https://ipfs-3speak.b-cdn.net'; - Future doesPostNotExist(String user, String post) async { - var request = http.Request('POST', Uri.parse(hiveApiUrl)); + Future doesPostNotExist( + String user, + String post, + String hiveApiUrl, + ) async { + var request = http.Request('POST', Uri.parse('https://$hiveApiUrl')); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", @@ -59,8 +63,8 @@ class Communicator { } } - Future getPublicKey(String user) async { - var request = http.Request('POST', Uri.parse(hiveApiUrl)); + Future getPublicKey(String user, String hiveApiUrl) async { + var request = http.Request('POST', Uri.parse('https://$hiveApiUrl')); request.body = json.encode({ "id": 8, "jsonrpc": "2.0", @@ -80,13 +84,16 @@ class Communicator { } } - Future> getListOfCommunities(String? query) async { + Future> getListOfCommunities( + String? query, + String hiveApiUrl, + ) async { var client = http.Client(); var body = CommunitiesRequestModel(params: CommunitiesRequestParams(query: query)) .toJsonString(); var response = - await client.post(Uri.parse(Communicator.hiveApiUrl), body: body); + await client.post(Uri.parse('https://$hiveApiUrl'), body: body); if (response.statusCode == 200) { var communitiesResponse = communitiesResponseModelFromString(response.body); @@ -96,8 +103,12 @@ class Communicator { } } - Future fetchHiveInfo(String user, String permlink) async { - var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); + Future fetchHiveInfo( + String user, + String permlink, + String hiveApiUrl, + ) async { + var request = http.Request('POST', Uri.parse('https://$hiveApiUrl')); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", @@ -203,11 +214,13 @@ class Communicator { const storage = FlutterSecureStorage(); await storage.write(key: 'cookie', value: cookie); String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; var newData = HiveUserData( username: user.username, postingKey: user.postingKey, cookie: cookie, resolution: resolution, + rpc: rpc, ); server.updateHiveUserData(newData); return cookie; @@ -233,11 +246,13 @@ class Communicator { const storage = FlutterSecureStorage(); await storage.delete(key: 'cookie'); String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; var newData = HiveUserData( username: user.username, postingKey: user.postingKey, cookie: null, resolution: resolution, + rpc: rpc, ); server.updateHiveUserData(newData); return await getValidCookie(newData); diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index 34f88077..bf0a6eba 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; -import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:provider/provider.dart'; @@ -39,13 +39,7 @@ class ListTileVideo extends StatefulWidget { } class _ListTileVideoState extends State { - late Future _fetchHiveInfo; - - @override - void initState() { - super.initState(); - _fetchHiveInfo = fetchHiveInfo(widget.user, widget.permlink); - } + Future? _fetchHiveInfo; Widget _errorIndicator() { return Container( @@ -59,8 +53,9 @@ class _ListTileVideoState extends State { ); } - Future fetchHiveInfo(String user, String permlink) async { - var request = http.Request('POST', Uri.parse(Communicator.hiveApiUrl)); + Future fetchHiveInfo( + String user, String permlink, String hiveApiUrl) async { + var request = http.Request('POST', Uri.parse('https://$hiveApiUrl')); request.body = json.encode({ "id": 1, "jsonrpc": "2.0", @@ -187,6 +182,12 @@ class _ListTileVideoState extends State { @override Widget build(BuildContext context) { + var user = Provider.of(context); + if (_fetchHiveInfo == null) { + setState(() { + _fetchHiveInfo = fetchHiveInfo(widget.user, widget.permlink, user.rpc); + }); + } return _thumbnailType(context); } } From d6cdcf3f0e5e600c803d8e1b705245d2e077c08c Mon Sep 17 00:00:00 2001 From: igormuba Date: Sat, 3 Dec 2022 15:03:19 -0300 Subject: [PATCH 137/466] Add share desktop app link to drawer When clicked on the "download desktop app" icon on the menu drawer the user will be able to share the download link for the desktop app --- lib/src/screens/drawer_screen/drawer_screen.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 97db5bc3..715da7fc 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -9,6 +9,7 @@ import 'package:acela/src/screens/settings/settings_screen.dart'; import 'package:acela/src/screens/stories/stories_screen.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:share_plus/share_plus.dart'; class DrawerScreen extends StatelessWidget { const DrawerScreen({Key? key}) : super(key: key); @@ -174,6 +175,17 @@ class DrawerScreen extends StatelessWidget { ); } + + Widget _desktopApp() { + return ListTile( + leading: const Icon(Icons.download), + title: const Text("Desktop App"), + onTap: () { + Share.share('Download 3Speak on desktop at https://github.com/spknetwork/3Speak-app'); + }, + ); + } + Widget _settings(BuildContext context) { return ListTile( leading: const Icon(Icons.settings), From 0329eecee0800d733f7fd41916c9414c24adef84 Mon Sep 17 00:00:00 2001 From: igormuba Date: Sat, 3 Dec 2022 15:10:56 -0300 Subject: [PATCH 138/466] Call function to render desktop app drawer --- lib/src/screens/drawer_screen/drawer_screen.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 715da7fc..8054eec6 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -224,6 +224,7 @@ class DrawerScreen extends StatelessWidget { _divider(), _shorts(context), _divider(), + _desktopApp(), _settings(context), _divider(), user.username == null ? _login(context) : _myAccount(context), From e943c9a1a432fa08732c2d93ed75d52b1cf26a34 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 6 Dec 2022 02:22:23 +0530 Subject: [PATCH 139/466] video player bug fixes. --- .flutter-plugins | 16 ++-- .flutter-plugins-dependencies | 2 +- .idea/libraries/Flutter_Plugins.xml | 10 +-- android/app/build.gradle | 2 + ios/Runner.xcodeproj/project.pbxproj | 12 +-- ios/Runner/Info.plist | 2 +- lib/src/screens/stories/stories_feed.dart | 73 +++++++------------ .../video_details_screen.dart | 6 +- lib/src/widgets/story_player.dart | 22 ++++-- lib/src/widgets/story_player_android.dart | 66 ----------------- lib/src/widgets/video_player.dart | 36 +-------- lib/src/widgets/video_player_android.dart | 48 ------------ pubspec.lock | 61 ++++++++-------- pubspec.yaml | 6 +- 14 files changed, 104 insertions(+), 258 deletions(-) delete mode 100644 lib/src/widgets/story_player_android.dart delete mode 100644 lib/src/widgets/video_player_android.dart diff --git a/.flutter-plugins b/.flutter-plugins index ba52c861..60c9dd4b 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,25 +1,25 @@ # This is a generated file; do not edit or check into version control. -better_player=/Users/sagar/.pub-cache/hosted/pub.dev/better_player-0.0.83/ +better_player=/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/ device_info_plus=/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/ device_info_plus_linux=/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/ device_info_plus_macos=/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/ device_info_plus_web=/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/ device_info_plus_windows=/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/ ffmpeg_kit_flutter=/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/ -file_picker=/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.2/ +file_picker=/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/ flutter_plugin_android_lifecycle=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/ -flutter_secure_storage=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.0.0/ -flutter_secure_storage_linux=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.1/ -flutter_secure_storage_macos=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.1/ -flutter_secure_storage_web=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.0.2/ -flutter_secure_storage_windows=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.2/ +flutter_secure_storage=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/ +flutter_secure_storage_linux=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/ +flutter_secure_storage_macos=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/ +flutter_secure_storage_web=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/ +flutter_secure_storage_windows=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/ image_picker=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker-0.8.6/ image_picker_android=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/ image_picker_for_web=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/ image_picker_ios=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/ images_picker=/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/ path_provider=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider-2.0.11/ -path_provider_android=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.21/ +path_provider_android=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/ path_provider_ios=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/ path_provider_linux=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/ path_provider_macos=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 2fc6ec52..49ca3a41 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/hosted/pub.dev/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.2/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.0.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/hosted/pub.dev/better_player-0.0.83/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.0.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.21/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.1/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.1/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.2/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.0.2/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-11-30 15:36:31.295840","version":"3.6.0-0.1.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-06 01:15:38.857566","version":"3.6.0-0.1.pre"} \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index c1e373b2..88fdd3a1 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,7 +1,6 @@ - @@ -9,16 +8,13 @@ - - - @@ -41,13 +37,17 @@ - + + + + + diff --git a/android/app/build.gradle b/android/app/build.gradle index 93662df4..ab159abb 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -53,6 +53,8 @@ android { buildTypes { release { + minifyEnabled false + shrinkResources false // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. signingConfig signingConfigs.debug diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8b7b5772..3b980272 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -392,7 +392,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 44; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -426,7 +426,7 @@ CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 44; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -475,7 +475,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 44; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -534,7 +534,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 44; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -570,7 +570,7 @@ CODE_SIGN_IDENTITY = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 44; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -600,7 +600,7 @@ CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 44; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index ad35f384..20fdeac0 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -23,7 +23,7 @@ CFBundleSignature ???? CFBundleVersion - 43 + 44 LSRequiresIPhoneOS LSSupportsOpeningDocumentsInPlace diff --git a/lib/src/screens/stories/stories_feed.dart b/lib/src/screens/stories/stories_feed.dart index 0e98e691..8e9b440c 100644 --- a/lib/src/screens/stories/stories_feed.dart +++ b/lib/src/screens/stories/stories_feed.dart @@ -1,11 +1,8 @@ -import 'dart:io'; - import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/story_player.dart'; -import 'package:acela/src/widgets/story_player_android.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; @@ -24,6 +21,8 @@ class StoriesFeedScreen extends StatefulWidget { class _StoriesFeedScreenState extends State { List items = []; var isLoading = false; + var initialPage = 0; + CarouselController controller = CarouselController(); @override void initState() { @@ -41,7 +40,7 @@ class _StoriesFeedScreenState extends State { List list = homeFeedItemFromString(response.body); setState(() { isLoading = false; - items = list.where((element) => element.duration < 180).toList(); + items = list.where((element) => element.duration <= 90).toList(); }); } else { showError('Status code ${response.statusCode}'); @@ -70,60 +69,44 @@ class _StoriesFeedScreenState extends State { } Widget _fullPost(HomeFeedItem item, HiveUserData data) { - return Platform.isAndroid - ? Stack( - children: [ - StoryPlayerAndroid( - playUrl: item.getVideoUrl(data), - thumbnail: item.images.thumbnail, - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height - widget.height, - ), - Container( - child: Row( - children: [ - const Spacer(), - Text('@${item.author}/${item.permlink}', - style: Theme.of(context).textTheme.titleLarge), - const Spacer(), - ], - ), - ) - ], - ) - : Stack( + return Stack( + children: [ + StoryPlayer( + playUrl: item.getVideoUrl(data), + thumbnail: item.images.thumbnail, + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - widget.height, + didFinish: () { + setState(() { + controller.nextPage(); + }); + }, + ), + Container( + child: Row( children: [ - StoryPlayer( - playUrl: item.getVideoUrl(data), - thumbnail: item.images.thumbnail, - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height - widget.height, + const Spacer(), + Text( + '@${item.author}/${item.permlink}', + style: Theme.of(context).textTheme.titleLarge, ), - Container( - child: Row( - children: [ - const Spacer(), - Text( - '@${item.author}/${item.permlink}', - style: Theme.of(context).textTheme.titleLarge, - ), - const Spacer(), - ], - ), - ) + const Spacer(), ], - ); + ), + ) + ], + ); } Widget carousel(HiveUserData data) { return Container( child: CarouselSlider( + carouselController: controller, options: CarouselOptions( height: MediaQuery.of(context).size.height, enableInfiniteScroll: false, viewportFraction: 1, scrollDirection: Axis.vertical, - // enlargeCenterPage: true, ), items: items.map((item) { return Builder( diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index ec0f7f89..cfc0d74a 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_comments/response/hive_comments.dart'; @@ -17,7 +16,6 @@ import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/video_player.dart'; -import 'package:acela/src/widgets/video_player_android.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:http/http.dart' as http; @@ -459,9 +457,7 @@ class _VideoDetailsScreenState extends State { videoWithDetails(data, userData), SizedBox( height: 230, - child: Platform.isAndroid - ? SPKVideoPlayerForAndroid(playUrl: url) - : SPKVideoPlayer(playUrl: url), + child: SPKVideoPlayer(playUrl: url), ), ], ), diff --git a/lib/src/widgets/story_player.dart b/lib/src/widgets/story_player.dart index 099cfd3d..c5e16144 100644 --- a/lib/src/widgets/story_player.dart +++ b/lib/src/widgets/story_player.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:better_player/better_player.dart'; import 'package:flutter/material.dart'; @@ -8,11 +10,13 @@ class StoryPlayer extends StatefulWidget { required this.thumbnail, required this.width, required this.height, + required this.didFinish, }) : super(key: key); final String playUrl; final String thumbnail; final double width; final double height; + final Function didFinish; @override _StoryPlayerState createState() => _StoryPlayerState(); @@ -20,7 +24,7 @@ class StoryPlayer extends StatefulWidget { class _StoryPlayerState extends State { late BetterPlayerController _betterPlayerController; - GlobalKey _betterPlayerKey = GlobalKey(); + late BetterPlayerConfiguration config; @override void dispose() { @@ -30,8 +34,7 @@ class _StoryPlayerState extends State { @override void initState() { - BetterPlayerConfiguration betterPlayerConfiguration = - BetterPlayerConfiguration( + config = BetterPlayerConfiguration( aspectRatio: widget.width / widget.height, fit: BoxFit.fitHeight, autoPlay: true, @@ -41,16 +44,24 @@ class _StoryPlayerState extends State { showControlsOnInitialize: false, ), fullScreenByDefault: false, + autoDispose: true, + eventListener: (event) { + log('type - ${event.betterPlayerEventType.toString()}'); + if (event.betterPlayerEventType == BetterPlayerEventType.finished) { + widget.didFinish(); + } + }, ); BetterPlayerDataSource dataSource = BetterPlayerDataSource( BetterPlayerDataSourceType.network, widget.playUrl, + videoFormat: BetterPlayerVideoFormat.hls, ); - _betterPlayerController = BetterPlayerController(betterPlayerConfiguration); + _betterPlayerController = BetterPlayerController(config); _betterPlayerController.setupDataSource(dataSource); - _betterPlayerController.setBetterPlayerGlobalKey(_betterPlayerKey); _betterPlayerController.setControlsEnabled(false); _betterPlayerController.setControlsAlwaysVisible(false); + super.initState(); } @@ -58,7 +69,6 @@ class _StoryPlayerState extends State { Widget build(BuildContext context) { return BetterPlayer( controller: _betterPlayerController, - key: _betterPlayerKey, ); } } diff --git a/lib/src/widgets/story_player_android.dart b/lib/src/widgets/story_player_android.dart deleted file mode 100644 index 19894cd0..00000000 --- a/lib/src/widgets/story_player_android.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:acela/src/widgets/loading_screen.dart'; -import 'package:chewie/chewie.dart'; -import 'package:flutter/material.dart'; -import 'package:video_player/video_player.dart'; - -class StoryPlayerAndroid extends StatefulWidget { - const StoryPlayerAndroid({ - Key? key, - required this.playUrl, - required this.thumbnail, - required this.width, - required this.height, - }) : super(key: key); - - final String playUrl; - final String thumbnail; - final double width; - final double height; - - @override - State createState() => _StoryPlayerAndroidState(); -} - -class _StoryPlayerAndroidState extends State { - late VideoPlayerController videoPlayerController; - ChewieController? chewieController; - - @override - void dispose() { - super.dispose(); - videoPlayerController.dispose(); - } - - @override - void initState() { - videoPlayerController = VideoPlayerController.network( - widget.playUrl, - videoPlayerOptions: VideoPlayerOptions( - allowBackgroundPlayback: false, - ), - )..initialize().then((_) { - setState(() { - chewieController = ChewieController( - videoPlayerController: videoPlayerController, - aspectRatio: widget.width / widget.height, - allowFullScreen: false, - allowPlaybackSpeedChanging: false, - showControls: false, - showControlsOnInitialize: false, - zoomAndPan: false, - showOptions: false, - autoPlay: true, - looping: true, - ); - }); - }); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return chewieController == null - ? const LoadingScreen(title: 'Loading Video', subtitle: 'Please wait') - : Chewie(controller: chewieController!); - } -} diff --git a/lib/src/widgets/video_player.dart b/lib/src/widgets/video_player.dart index 4cd315f4..ccf74476 100644 --- a/lib/src/widgets/video_player.dart +++ b/lib/src/widgets/video_player.dart @@ -13,40 +13,7 @@ class SPKVideoPlayer extends StatefulWidget { } class _SPKVideoPlayerState extends State { - // late VideoPlayerController videoPlayerController; - // ChewieController? chewieController; late BetterPlayerController _betterPlayerController; - GlobalKey _betterPlayerKey = GlobalKey(); - - // @override - // void dispose() { - // super.dispose(); - // videoPlayerController.dispose(); - // } - - // @override - // void initState() { - // videoPlayerController = VideoPlayerController.network(widget.playUrl, - // videoPlayerOptions: VideoPlayerOptions(allowBackgroundPlayback: true)) - // ..initialize().then((_) { - // setState(() { - // chewieController = ChewieController( - // videoPlayerController: videoPlayerController, - // autoPlay: true, - // looping: false, - // ); - // }); - // }); - // super.initState(); - // } - - // @override - // Widget build(BuildContext context) { - // return chewieController == null - // ? const LoadingScreen() - // : Chewie(controller: chewieController!); - // } - @override void initState() { BetterPlayerConfiguration betterPlayerConfiguration = @@ -57,10 +24,10 @@ class _SPKVideoPlayerState extends State { BetterPlayerDataSource dataSource = BetterPlayerDataSource( BetterPlayerDataSourceType.network, widget.playUrl, + videoFormat: BetterPlayerVideoFormat.hls, ); _betterPlayerController = BetterPlayerController(betterPlayerConfiguration); _betterPlayerController.setupDataSource(dataSource); - _betterPlayerController.setBetterPlayerGlobalKey(_betterPlayerKey); super.initState(); } @@ -68,7 +35,6 @@ class _SPKVideoPlayerState extends State { Widget build(BuildContext context) { return BetterPlayer( controller: _betterPlayerController, - key: _betterPlayerKey, ); } } diff --git a/lib/src/widgets/video_player_android.dart b/lib/src/widgets/video_player_android.dart deleted file mode 100644 index 83f3901c..00000000 --- a/lib/src/widgets/video_player_android.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:acela/src/widgets/loading_screen.dart'; -import 'package:chewie/chewie.dart'; -import 'package:flutter/material.dart'; -import 'package:video_player/video_player.dart'; - -class SPKVideoPlayerForAndroid extends StatefulWidget { - const SPKVideoPlayerForAndroid({Key? key, required this.playUrl}) - : super(key: key); - final String playUrl; - - @override - _SPKVideoPlayerForAndroidState createState() => - _SPKVideoPlayerForAndroidState(); -} - -class _SPKVideoPlayerForAndroidState extends State { - late VideoPlayerController videoPlayerController; - ChewieController? chewieController; - - @override - void dispose() { - super.dispose(); - videoPlayerController.dispose(); - } - - @override - void initState() { - videoPlayerController = VideoPlayerController.network(widget.playUrl, - videoPlayerOptions: VideoPlayerOptions(allowBackgroundPlayback: true)) - ..initialize().then((_) { - setState(() { - chewieController = ChewieController( - videoPlayerController: videoPlayerController, - autoPlay: true, - looping: false, - ); - }); - }); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return chewieController == null - ? const LoadingScreen(title: 'Loading Video', subtitle: 'Please wait') - : Chewie(controller: chewieController!); - } -} diff --git a/pubspec.lock b/pubspec.lock index 4d271479..c3ca9b7d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -52,10 +52,11 @@ packages: better_player: dependency: "direct main" description: - name: better_player - sha256: f2e5d57ea49fb7c4d93838d23846ca5ddf78af6f946e103aeacf2afdd01909b3 - url: "https://pub.dev" - source: hosted + path: "." + ref: HEAD + resolved-ref: "91a9625524cdff448e0a9deb5047bcf20cc8dcf1" + url: "https://github.com/tintran-dev/betterplayer.git" + source: git version: "0.0.83" boolean_selector: dependency: transitive @@ -181,10 +182,10 @@ packages: dependency: "direct main" description: name: chewie - sha256: edb7a38d3f80035e46f931a6ff9391706e206f81f7c00ca4d58356809b593427 + sha256: "7737b1b8b1f9df3b3751abfb0dea5efbebb7060c28eccdc3b0fa4a0d638eaf9f" url: "https://pub.dev" source: hosted - version: "1.3.5" + version: "1.3.6" clock: dependency: transitive description: @@ -357,10 +358,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: c24465c112b1a31a37ac450afc2e1f927b7c11599beab93233d7ffb449373fe3 + sha256: "28f1c95692761e7b582d83d40da61295d489f4be0a368b2746ed2cdfe87e7fef" url: "https://pub.dev" source: hosted - version: "5.2.2" + version: "5.2.3" fixnum: dependency: transitive description: @@ -410,50 +411,50 @@ packages: dependency: "direct main" description: name: flutter_secure_storage - sha256: a12d0213eab6848033b824fce82ef33229ec638debae46ef3d570d8b1146949b + sha256: de957362e046bc68da8dcf6c1d922cb8bdad8dd4979ec69480cf1a3c481abe8e url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "6.1.0" flutter_secure_storage_linux: dependency: transitive description: name: flutter_secure_storage_linux - sha256: "7b36defaed0a994cc58d6a169a7c89c695ea660ef86903df13c2a2708fb1e1bb" + sha256: "736436adaf91552433823f51ce22e098c2f0551db06b6596f58597a25b8ea797" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" flutter_secure_storage_macos: dependency: transitive description: name: flutter_secure_storage_macos - sha256: cd8eff6ebb4d9083aa3a57f29da00df837a869e8d5c65d9ad1ce549037c55d06 + sha256: "388f76fd0f093e7415a39ec4c169ae7cceeee6d9f9ba529d788a13f2be4de7bd" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" flutter_secure_storage_platform_interface: dependency: transitive description: name: flutter_secure_storage_platform_interface - sha256: "9af003dec5ba9f959300fd76ac8adf5608fbfbc957cdd7a987af206a8e073b32" + sha256: b3773190e385a3c8a382007893d678ae95462b3c2279e987b55d140d3b0cb81b url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" flutter_secure_storage_web: dependency: transitive description: name: flutter_secure_storage_web - sha256: "926716d84eb45220cb1783af629093301613f5e5b51da7c1813e430d69bd716f" + sha256: "42938e70d4b872e856e678c423cc0e9065d7d294f45bc41fc1981a4eb4beaffe" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.1" flutter_secure_storage_windows: dependency: transitive description: name: flutter_secure_storage_windows - sha256: cf9fd49c2807f80dc01f449592e1e7971a3697d1e248b653efb8323536dc2961 + sha256: ca89c8059cf439985aa83c59619b3674c7ef6cc2e86943d169a7369d6a69cab5 url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.3" flutter_test: dependency: "direct dev" description: flutter @@ -476,18 +477,18 @@ packages: dependency: "direct main" description: name: font_awesome_flutter - sha256: "8f0ce0204bd0cafa8631536a6f3b7d05d9c16cdc6e8bd807843f917027c5cefd" + sha256: "875dbb9ec1ad30d68102019ceb682760d06c72747c1c5b7885781b95f88569cc" url: "https://pub.dev" source: hosted - version: "10.2.1" + version: "10.3.0" frontend_server_client: dependency: transitive description: name: frontend_server_client - sha256: "82715f8041a85a534a7bf64400b2ee0bb3d594ccf695d97c0bb017259657ff5d" + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.0" fwfh_text_style: dependency: transitive description: @@ -700,10 +701,10 @@ packages: dependency: transitive description: name: mime - sha256: dab22e92b41aa1255ea90ddc4bc2feaf35544fd0728e209638cad041a6e3928a + sha256: "52e38f7e1143ef39daf532117d6b8f8f617bf4bcd6044ed8c29040d20d269630" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.3" nested: dependency: transitive description: @@ -748,10 +749,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "1dab723dd8feeb80afb39c7be894f09df1457243d930010f6f328fb8c660c5e1" + sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e url: "https://pub.dev" source: hosted - version: "2.0.21" + version: "2.0.22" path_provider_ios: dependency: transitive description: @@ -1338,10 +1339,10 @@ packages: dependency: transitive description: name: win32 - sha256: d13ac5deea7327f027b3b97ee19ee210f68256ecf3f1a304bcfb992ee947637c + sha256: ca121dbbadb3e43b449053feab0cdf3f2bff93b107cacf0290e3d29f717374b6 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5c2c55e9..a0ccb73d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.3+44 +version: 1.0.3+45 environment: sdk: ">=2.15.1 <3.0.0" @@ -28,7 +28,9 @@ environment: # versions available, run `flutter pub outdated`. dependencies: adaptive_action_sheet: ^2.0.1 - better_player: ^0.0.83 + better_player: + git: + url: https://github.com/tintran-dev/betterplayer.git bs58: ^1.0.2 bs58check: ^1.0.2 chewie: ^1.3.0 From 1dbbac004859daca1b6d53a4f2fc0c8dc6701a3e Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 8 Dec 2022 04:49:41 +0530 Subject: [PATCH 140/466] Details updated. --- .flutter-plugins-dependencies | 2 +- ios/Podfile.lock | 4 +-- ios/Runner.xcodeproj/project.pbxproj | 12 ++++---- ios/Runner/Info.plist | 2 +- ios/app.json | 44 ++++++++++++++++++++++++++++ pubspec.yaml | 2 +- 6 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 ios/app.json diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 49ca3a41..27f6ddb7 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-06 01:15:38.857566","version":"3.6.0-0.1.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-07 20:05:13.408795","version":"3.6.0-0.1.pre"} \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d9b5d63d..7340dfb8 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -50,7 +50,7 @@ PODS: - DKImagePickerController/PhotoGallery - Flutter - Flutter (1.0.0) - - flutter_secure_storage (3.3.1): + - flutter_secure_storage (6.0.0): - Flutter - FYVideoCompressor (0.0.7) - GCDWebServer (3.5.4): @@ -190,7 +190,7 @@ SPEC CHECKSUMS: ffmpeg_kit_flutter: e2f0bd6b75e361faeee3b34c70650d3ec6ec35d0 file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec + flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be FYVideoCompressor: 70440458b5fe699f05e4a8a9011f1e4080056330 GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4 HLSCachingReverseProxyServer: 59935e1e0244ad7f3375d75b5ef46e8eb26ab181 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 3b980272..ece97fea 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -392,7 +392,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 44; + CURRENT_PROJECT_VERSION = 52; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -426,7 +426,7 @@ CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 44; + CURRENT_PROJECT_VERSION = 52; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -475,7 +475,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 44; + CURRENT_PROJECT_VERSION = 52; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -534,7 +534,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 44; + CURRENT_PROJECT_VERSION = 52; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -570,7 +570,7 @@ CODE_SIGN_IDENTITY = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 44; + CURRENT_PROJECT_VERSION = 52; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -600,7 +600,7 @@ CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 44; + CURRENT_PROJECT_VERSION = 52; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 20fdeac0..353fa3c1 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -23,7 +23,7 @@ CFBundleSignature ???? CFBundleVersion - 44 + 52 LSRequiresIPhoneOS LSSupportsOpeningDocumentsInPlace diff --git a/ios/app.json b/ios/app.json new file mode 100644 index 00000000..3ca823ff --- /dev/null +++ b/ios/app.json @@ -0,0 +1,44 @@ +{ + "name": "3Speak - Acela Source", + "identifier": "com.example.acela", + "sourceURL": "https://github.com/noah978/AltStore-Docs/raw/master/apps.json", + "apps": [ + { + "name": "3Speak.tv - Acela", + "bundleIdentifier": "com.example.acela", + "developerName": "sagarkothari88", + "subtitle": "Tokenized Video Communities", + "version": "1.0.3", + "versionDate": "2022-12-08", + "versionDescription": "https://ecency.com/hive-181335/@sagarkothari88/3speak-development-update-from-sagarkothari88-7cd51a3b88448", + "downloadURL": "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/Runner.ipa", + "localizedDescription": "The build which was also submitted to the Apple for TestFlight review", + "iconURL": "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/AppIcon-512.png", + "tintColor": "afeeee", + "size": 857669, + "permissions": [ + ], + "screenshotURLs": [ + "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/IMG_5651.PNG", + "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/IMG_5652.PNG", + "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/IMG_5653.PNG", + "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/IMG_5654.PNG", + "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/IMG_5655.PNG", + ], + "beta": false + } + ], + "news": [ + { + "title": "3Speak.tv Acela - Download now - via AltStore", + "identifier": "3speak-tv-acela-download-2022-12-08", + "caption": "3Speak.tv Acela release via AltStore", + "date": "2022-12-08", + "tintColor": "afeeee", + "imageURL": "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/AppIcon-512.png", + "url": "https://ecency.com/hive-181335/@sagarkothari88/3speak-development-update-from-sagarkothari88-7cd51a3b88448", + "appID": "com.example.acela", + "notify": true + } + ] +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index a0ccb73d..05f77fda 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.3+45 +version: 1.0.3+46 environment: sdk: ">=2.15.1 <3.0.0" From a3e37259d1322aba0e215d7f311d2781d5e8515b Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 9 Dec 2022 10:14:27 +0530 Subject: [PATCH 141/466] changes --- ios/app.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/app.json b/ios/app.json index 3ca823ff..57decdda 100644 --- a/ios/app.json +++ b/ios/app.json @@ -1,7 +1,7 @@ { "name": "3Speak - Acela Source", "identifier": "com.example.acela", - "sourceURL": "https://github.com/noah978/AltStore-Docs/raw/master/apps.json", + "sourceURL": "https://github.com/spknetwork/Android-App/raw/development/ios/app.json", "apps": [ { "name": "3Speak.tv - Acela", @@ -14,7 +14,7 @@ "downloadURL": "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/Runner.ipa", "localizedDescription": "The build which was also submitted to the Apple for TestFlight review", "iconURL": "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/AppIcon-512.png", - "tintColor": "afeeee", + "tintColor": "AFEEEE", "size": 857669, "permissions": [ ], From 3f35ab57643c1d583178708d58a07cd7c53ca964 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 18 Dec 2022 18:29:22 +0530 Subject: [PATCH 142/466] Fixed followings. - App > 3Shorts > Infinite 3Shorts - App > 3Shorts > Portrait & Landscape shorts support on 3Shorts --- .flutter-plugins-dependencies | 2 +- .../models/stories/stories_feed_response.dart | 91 +++++++++++++++++++ .../screens/drawer_screen/drawer_screen.dart | 7 +- lib/src/screens/stories/stories_feed.dart | 45 ++++++--- lib/src/screens/stories/stories_screen.dart | 52 ++++++++--- lib/src/widgets/story_player.dart | 33 ++++--- pubspec.lock | 8 +- 7 files changed, 185 insertions(+), 53 deletions(-) create mode 100644 lib/src/models/stories/stories_feed_response.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 27f6ddb7..7d0d548b 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-07 20:05:13.408795","version":"3.6.0-0.1.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-18 17:56:41.568519","version":"3.7.0-1.1.pre"} \ No newline at end of file diff --git a/lib/src/models/stories/stories_feed_response.dart b/lib/src/models/stories/stories_feed_response.dart new file mode 100644 index 00000000..b514e047 --- /dev/null +++ b/lib/src/models/stories/stories_feed_response.dart @@ -0,0 +1,91 @@ +import 'dart:convert'; + +import 'package:acela/src/utils/safe_convert.dart'; + +class StoriesFeedResponseItem { + final bool fromMobile; + final bool isReel; + final String id; + final String filename; + final String originalFilename; + final String permlink; + final double duration; + final int size; + final String owner; + final String uploadType; + final int v; + final String description; + final String tags; + final String thumbnail; + final String title; + final String thumbUrl; + final String baseThumbUrl; + final String playUrl; + final String publishData; + final String localFilename; + final String jobId; + + StoriesFeedResponseItem({ + this.fromMobile = false, + this.isReel = false, + this.id = "", + this.filename = "", + this.originalFilename = "", + this.permlink = "", + this.duration = 0.0, + this.size = 0, + this.owner = "", + this.uploadType = "", + this.v = 0, + this.description = "", + this.tags = "", + this.thumbnail = "", + this.title = "", + this.thumbUrl = "", + this.baseThumbUrl = "", + this.playUrl = "", + this.publishData = "", + this.localFilename = "", + this.jobId = "", + }); + + List fromJsonString(String jsonString, String type) { + if (type == 'feed') { + final jsonList = json.decode(jsonString) as List; + return jsonList.map((e) => StoriesFeedResponseItem.fromJson(e)).toList(); + } else if (type == 'trends') { + final jsonObj = json.decode(jsonString) as Map; + final jsonList = jsonObj['trends'] as List; + return jsonList.map((e) => StoriesFeedResponseItem.fromJson(e)).toList(); + } else { + final jsonObj = json.decode(jsonString) as Map; + final jsonList = jsonObj['recommended'] as List; + return jsonList.map((e) => StoriesFeedResponseItem.fromJson(e)).toList(); + } + } + + factory StoriesFeedResponseItem.fromJson(Map? json) => + StoriesFeedResponseItem( + fromMobile: asBool(json, 'fromMobile'), + isReel: asBool(json, 'isReel'), + id: asString(json, '_id'), + filename: asString(json, 'filename'), + originalFilename: asString(json, 'originalFilename'), + permlink: asString(json, 'permlink'), + duration: asDouble(json, 'duration'), + size: asInt(json, 'size'), + owner: asString(json, 'owner'), + uploadType: asString(json, 'upload_type'), + v: asInt(json, '__v'), + description: asString(json, 'description'), + tags: asString(json, 'tags'), + thumbnail: asString(json, 'thumbnail'), + title: asString(json, 'title'), + thumbUrl: asString(json, 'thumbUrl'), + baseThumbUrl: asString(json, 'baseThumbUrl'), + playUrl: asString(json, 'playUrl'), + publishData: asString(json, 'publish_data'), + localFilename: asString(json, 'local_filename'), + jobId: asString(json, 'job_id'), + ); +} diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 8054eec6..44a0d7e5 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -175,13 +175,13 @@ class DrawerScreen extends StatelessWidget { ); } - Widget _desktopApp() { return ListTile( leading: const Icon(Icons.download), title: const Text("Desktop App"), onTap: () { - Share.share('Download 3Speak on desktop at https://github.com/spknetwork/3Speak-app'); + Share.share( + 'Download 3Speak on desktop at https://github.com/spknetwork/3Speak-app'); }, ); } @@ -224,13 +224,14 @@ class DrawerScreen extends StatelessWidget { _divider(), _shorts(context), _divider(), - _desktopApp(), _settings(context), _divider(), user.username == null ? _login(context) : _myAccount(context), _divider(), _importantLinks(context), _divider(), + _desktopApp(), + _divider(), ], ); } diff --git a/lib/src/screens/stories/stories_feed.dart b/lib/src/screens/stories/stories_feed.dart index 8e9b440c..e1ee7859 100644 --- a/lib/src/screens/stories/stories_feed.dart +++ b/lib/src/screens/stories/stories_feed.dart @@ -1,5 +1,5 @@ import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; +import 'package:acela/src/models/stories/stories_feed_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/story_player.dart'; @@ -9,17 +9,22 @@ import 'package:http/http.dart'; import 'package:provider/provider.dart'; class StoriesFeedScreen extends StatefulWidget { - const StoriesFeedScreen({Key? key, required this.type, required this.height}) - : super(key: key); + const StoriesFeedScreen({ + Key? key, + required this.type, + required this.height, + required this.fitWidth, + }) : super(key: key); final String type; final double height; + final bool fitWidth; @override State createState() => _StoriesFeedScreenState(); } class _StoriesFeedScreenState extends State { - List items = []; + List items = []; var isLoading = false; var initialPage = 0; CarouselController controller = CarouselController(); @@ -27,20 +32,30 @@ class _StoriesFeedScreenState extends State { @override void initState() { super.initState(); - loadData(); + loadData(0); } - void loadData() async { + void loadData(int length) async { setState(() { isLoading = true; }); - var response = await get( - Uri.parse('${server.domain}/apiv2/feeds/${widget.type}?isReel=true')); + var string = '${server.domain}/api/${widget.type}/more?skip=$length'; + var response = await get(Uri.parse(string)); if (response.statusCode == 200) { - List list = homeFeedItemFromString(response.body); + List list = + StoriesFeedResponseItem().fromJsonString(response.body, widget.type); setState(() { isLoading = false; - items = list.where((element) => element.duration <= 90).toList(); + items = items + + list + .where((element) => + element.duration <= 90 || element.isReel == true) + .toList(); + var permlinks = Set(); + items.retainWhere((x) => permlinks.add(x.permlink)); + if (items.length < 10) { + loadData(length + list.length); + } }); } else { showError('Status code ${response.statusCode}'); @@ -68,14 +83,14 @@ class _StoriesFeedScreenState extends State { ); } - Widget _fullPost(HomeFeedItem item, HiveUserData data) { + Widget _fullPost(StoriesFeedResponseItem item, HiveUserData data) { return Stack( children: [ StoryPlayer( - playUrl: item.getVideoUrl(data), - thumbnail: item.images.thumbnail, + playUrl: item.playUrl, width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height - widget.height, + fitWidth: widget.fitWidth, didFinish: () { setState(() { controller.nextPage(); @@ -87,7 +102,7 @@ class _StoriesFeedScreenState extends State { children: [ const Spacer(), Text( - '@${item.author}/${item.permlink}', + '@${item.owner}/${item.permlink}', style: Theme.of(context).textTheme.titleLarge, ), const Spacer(), @@ -104,7 +119,7 @@ class _StoriesFeedScreenState extends State { carouselController: controller, options: CarouselOptions( height: MediaQuery.of(context).size.height, - enableInfiniteScroll: false, + enableInfiniteScroll: true, viewportFraction: 1, scrollDirection: Axis.vertical, ), diff --git a/lib/src/screens/stories/stories_screen.dart b/lib/src/screens/stories/stories_screen.dart index c1362ca8..591eb1e7 100644 --- a/lib/src/screens/stories/stories_screen.dart +++ b/lib/src/screens/stories/stories_screen.dart @@ -10,19 +10,11 @@ class StoriesScreen extends StatefulWidget { class _StoriesScreenState extends State { static const List tabs = [ - Tab( - // text: 'Trending', - icon: const Icon(Icons.local_fire_department), - ), - Tab( - // text: 'New', - icon: const Icon(Icons.play_arrow), - ), - Tab( - // text: 'First Time', - icon: const Icon(Icons.emoji_emotions_outlined), - ), + Tab(icon: const Icon(Icons.home)), + Tab(icon: const Icon(Icons.trending_up)), + Tab(icon: const Icon(Icons.new_label)), ]; + var fitWidth = true; @override Widget build(BuildContext context) { @@ -43,6 +35,24 @@ class _StoriesScreenState extends State { const Text('3Shorts') ], ), + actions: [ + fitWidth + ? IconButton( + onPressed: () { + setState(() { + fitWidth = false; + }); + }, + icon: Icon(Icons.screenshot)) + : IconButton( + onPressed: () { + setState(() { + fitWidth = true; + }); + }, + icon: Icon(Icons.smart_screen), + ) + ], bottom: TabBar( tabs: tabs, ), @@ -52,9 +62,21 @@ class _StoriesScreenState extends State { appBar: appBar, body: TabBarView( children: [ - StoriesFeedScreen(type: 'trending', height: height), - StoriesFeedScreen(type: 'new', height: height), - StoriesFeedScreen(type: 'firstUploads', height: height), + StoriesFeedScreen( + type: 'feed', + height: height, + fitWidth: fitWidth, + ), + StoriesFeedScreen( + type: 'trends', + height: height, + fitWidth: fitWidth, + ), + StoriesFeedScreen( + type: 'new', + height: height, + fitWidth: fitWidth, + ), ], ), ); diff --git a/lib/src/widgets/story_player.dart b/lib/src/widgets/story_player.dart index c5e16144..e2a91ad2 100644 --- a/lib/src/widgets/story_player.dart +++ b/lib/src/widgets/story_player.dart @@ -4,19 +4,19 @@ import 'package:better_player/better_player.dart'; import 'package:flutter/material.dart'; class StoryPlayer extends StatefulWidget { - const StoryPlayer({ - Key? key, - required this.playUrl, - required this.thumbnail, - required this.width, - required this.height, - required this.didFinish, - }) : super(key: key); + const StoryPlayer( + {Key? key, + required this.playUrl, + required this.width, + required this.height, + required this.didFinish, + required this.fitWidth}) + : super(key: key); final String playUrl; - final String thumbnail; final double width; final double height; final Function didFinish; + final bool fitWidth; @override _StoryPlayerState createState() => _StoryPlayerState(); @@ -35,16 +35,19 @@ class _StoryPlayerState extends State { @override void initState() { config = BetterPlayerConfiguration( - aspectRatio: widget.width / widget.height, + aspectRatio: widget.fitWidth + ? widget.height / widget.width + : widget.width / widget.height, fit: BoxFit.fitHeight, autoPlay: true, - // fullScreenByDefault: true, controlsConfiguration: BetterPlayerControlsConfiguration( - showControls: false, - showControlsOnInitialize: false, + showControls: true, + showControlsOnInitialize: true, ), fullScreenByDefault: false, autoDispose: true, + showPlaceholderUntilPlay: true, + allowedScreenSleep: false, eventListener: (event) { log('type - ${event.betterPlayerEventType.toString()}'); if (event.betterPlayerEventType == BetterPlayerEventType.finished) { @@ -59,8 +62,8 @@ class _StoryPlayerState extends State { ); _betterPlayerController = BetterPlayerController(config); _betterPlayerController.setupDataSource(dataSource); - _betterPlayerController.setControlsEnabled(false); - _betterPlayerController.setControlsAlwaysVisible(false); + // _betterPlayerController.setControlsEnabled(false); + // _betterPlayerController.setControlsAlwaysVisible(false); super.initState(); } diff --git a/pubspec.lock b/pubspec.lock index c3ca9b7d..775f5d98 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1035,10 +1035,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "862015c5db1f3f3c4ea3b94dc2490363a84262994b88902315ed74be1155612f" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: @@ -1051,10 +1051,10 @@ packages: dependency: transitive description: name: test_api - sha256: c9aba3b3dbfe8878845dfab5fa096eb8de7b62231baeeb1cea8e3ee81ca8c6d8 + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 url: "https://pub.dev" source: hosted - version: "0.4.15" + version: "0.4.16" timeago: dependency: "direct main" description: From 0a3c962a417f3879ae83360bd2f94d51d4998c86 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 18 Dec 2022 19:01:44 +0530 Subject: [PATCH 143/466] Added following feature. - App > 3Shorts > button to Share --- lib/src/screens/stories/stories_feed.dart | 90 +++++++++++++++++++---- lib/src/widgets/fab_custom.dart | 33 +++++++++ lib/src/widgets/fab_overlay.dart | 82 +++++++++++++++++++++ 3 files changed, 189 insertions(+), 16 deletions(-) create mode 100644 lib/src/widgets/fab_custom.dart create mode 100644 lib/src/widgets/fab_overlay.dart diff --git a/lib/src/screens/stories/stories_feed.dart b/lib/src/screens/stories/stories_feed.dart index e1ee7859..833f8c78 100644 --- a/lib/src/screens/stories/stories_feed.dart +++ b/lib/src/screens/stories/stories_feed.dart @@ -1,12 +1,15 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/stories/stories_feed_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/widgets/fab_custom.dart'; +import 'package:acela/src/widgets/fab_overlay.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/story_player.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; import 'package:provider/provider.dart'; +import 'package:share_plus/share_plus.dart'; class StoriesFeedScreen extends StatefulWidget { const StoriesFeedScreen({ @@ -28,6 +31,7 @@ class _StoriesFeedScreenState extends State { var isLoading = false; var initialPage = 0; CarouselController controller = CarouselController(); + bool isFilterMenuOn = false; @override void initState() { @@ -83,6 +87,57 @@ class _StoriesFeedScreenState extends State { ); } + List _fabItems( + StoriesFeedResponseItem item, HiveUserData data) { + List fabItems = []; + fabItems.add( + FabOverItemData( + displayName: 'Share', + icon: Icons.share, + onTap: () { + setState(() { + isFilterMenuOn = false; + Share.share( + 'https://3speak.tv/watch?v=${item.owner}/${item.permlink}'); + }); + }, + ), + ); + fabItems.add( + FabOverItemData( + displayName: 'Close', + icon: Icons.close, + onTap: () { + setState(() { + isFilterMenuOn = false; + }); + }, + ), + ); + return fabItems; + } + + Widget _fabContainer(StoriesFeedResponseItem item, HiveUserData data) { + if (!isFilterMenuOn) { + return FabCustom( + icon: Icons.bolt, + onTap: () { + setState(() { + isFilterMenuOn = true; + }); + }, + ); + } + return FabOverlay( + items: _fabItems(item, data), + onBackgroundTap: () { + setState(() { + isFilterMenuOn = false; + }); + }, + ); + } + Widget _fullPost(StoriesFeedResponseItem item, HiveUserData data) { return Stack( children: [ @@ -108,28 +163,31 @@ class _StoriesFeedScreenState extends State { const Spacer(), ], ), - ) + ), + _fabContainer(item, data), ], ); } Widget carousel(HiveUserData data) { - return Container( - child: CarouselSlider( - carouselController: controller, - options: CarouselOptions( - height: MediaQuery.of(context).size.height, - enableInfiniteScroll: true, - viewportFraction: 1, - scrollDirection: Axis.vertical, + return SafeArea( + child: Container( + child: CarouselSlider( + carouselController: controller, + options: CarouselOptions( + height: MediaQuery.of(context).size.height, + enableInfiniteScroll: true, + viewportFraction: 1, + scrollDirection: Axis.vertical, + ), + items: items.map((item) { + return Builder( + builder: (BuildContext context) { + return _fullPost(item, data); + }, + ); + }).toList(), ), - items: items.map((item) { - return Builder( - builder: (BuildContext context) { - return _fullPost(item, data); - }, - ); - }).toList(), ), ); } diff --git a/lib/src/widgets/fab_custom.dart b/lib/src/widgets/fab_custom.dart new file mode 100644 index 00000000..cb063eac --- /dev/null +++ b/lib/src/widgets/fab_custom.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; + +class FabCustom extends StatelessWidget { + const FabCustom({ + Key? key, + required this.icon, + required this.onTap, + }) : super(key: key); + final IconData icon; + final Function onTap; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + const Spacer(), + Row( + children: [ + const Spacer(), + FloatingActionButton( + onPressed: () { + onTap(); + }, + child: Icon(icon), + ), + const SizedBox(width: 10), + ], + ), + const SizedBox(height: 10), + ], + ); + } +} diff --git a/lib/src/widgets/fab_overlay.dart b/lib/src/widgets/fab_overlay.dart new file mode 100644 index 00000000..84f02d75 --- /dev/null +++ b/lib/src/widgets/fab_overlay.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class FabOverItemData { + String displayName; + IconData icon; + Function onTap; + + FabOverItemData({ + required this.displayName, + required this.icon, + required this.onTap, + }); +} + +class FabOverlay extends StatelessWidget { + const FabOverlay({ + Key? key, + required this.items, + required this.onBackgroundTap, + }) : super(key: key); + final List items; + final Function onBackgroundTap; + + Widget _singleItem(BuildContext context, FabOverItemData data) { + return Column( + children: [ + const SizedBox(height: 5), + Row( + children: [ + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(10)), + color: Theme.of(context).backgroundColor, + ), + child: Text(data.displayName), + ), + const SizedBox(width: 5), + FloatingActionButton( + mini: true, + onPressed: () { + data.onTap(); + }, + child: Icon(data.icon), + ), + ], + ), + ], + ); + } + + @override + Widget build(BuildContext context) { + var widgets = items.map((e) => _singleItem(context, e)).toList(); + return InkWell( + onTap: () { + onBackgroundTap(); + }, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor.withAlpha(200), + ), + child: Row( + children: [ + const Spacer(), + Column( + children: [ + const Spacer(), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: widgets, + ), + const SizedBox(height: 10) + ], + ), + const SizedBox(width: 10), + ], + ), + ), + ); + } +} From 94ada098f3fd0280bb3d8e0fa2f501a6ee286fb2 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 19 Dec 2022 11:43:52 +0530 Subject: [PATCH 144/466] Added followings - App > 3Shorts > button to view comments - App > 3Shorts > Investigate black 3Shorts - App > 3Shorts > button to view shorts info / hive post details --- .flutter-plugins-dependencies | 2 +- .../models/stories/stories_feed_response.dart | 6 +++ lib/src/screens/stories/stories_feed.dart | 37 ++++++++++++++++--- .../video_details_comments.dart | 4 +- .../video_details_info.dart | 27 ++++++++++---- .../video_details_screen.dart | 5 ++- 6 files changed, 65 insertions(+), 16 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 7d0d548b..f0abc051 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-18 17:56:41.568519","version":"3.7.0-1.1.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-18 22:58:47.231618","version":"3.7.0-1.1.pre"} \ No newline at end of file diff --git a/lib/src/models/stories/stories_feed_response.dart b/lib/src/models/stories/stories_feed_response.dart index b514e047..25a950e9 100644 --- a/lib/src/models/stories/stories_feed_response.dart +++ b/lib/src/models/stories/stories_feed_response.dart @@ -24,6 +24,8 @@ class StoriesFeedResponseItem { final String publishData; final String localFilename; final String jobId; + final String created; + final int views; StoriesFeedResponseItem({ this.fromMobile = false, @@ -47,6 +49,8 @@ class StoriesFeedResponseItem { this.publishData = "", this.localFilename = "", this.jobId = "", + this.created = "", + this.views = 0, }); List fromJsonString(String jsonString, String type) { @@ -87,5 +91,7 @@ class StoriesFeedResponseItem { publishData: asString(json, 'publish_data'), localFilename: asString(json, 'local_filename'), jobId: asString(json, 'job_id'), + created: asString(json, 'created'), + views: asInt(json, 'views'), ); } diff --git a/lib/src/screens/stories/stories_feed.dart b/lib/src/screens/stories/stories_feed.dart index 833f8c78..c2fe0df7 100644 --- a/lib/src/screens/stories/stories_feed.dart +++ b/lib/src/screens/stories/stories_feed.dart @@ -1,6 +1,8 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/stories/stories_feed_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_comments.dart'; +import 'package:acela/src/screens/video_details_screen/video_details_info.dart'; import 'package:acela/src/widgets/fab_custom.dart'; import 'package:acela/src/widgets/fab_overlay.dart'; import 'package:acela/src/widgets/loading_screen.dart'; @@ -89,8 +91,7 @@ class _StoriesFeedScreenState extends State { List _fabItems( StoriesFeedResponseItem item, HiveUserData data) { - List fabItems = []; - fabItems.add( + List fabItems = [ FabOverItemData( displayName: 'Share', icon: Icons.share, @@ -102,8 +103,34 @@ class _StoriesFeedScreenState extends State { }); }, ), - ); - fabItems.add( + FabOverItemData( + displayName: 'Info', + icon: Icons.info, + onTap: () { + setState(() { + isFilterMenuOn = false; + var screen = VideoDetailsInfoWidget(details: null, item: item); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }); + }, + ), + FabOverItemData( + displayName: 'Comments', + icon: Icons.comment, + onTap: () { + setState(() { + isFilterMenuOn = false; + var screen = VideoDetailsComments( + author: item.owner, + permlink: item.permlink, + rpc: data.rpc, + ); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }); + }, + ), FabOverItemData( displayName: 'Close', icon: Icons.close, @@ -113,7 +140,7 @@ class _StoriesFeedScreenState extends State { }); }, ), - ); + ]; return fabItems; } diff --git a/lib/src/screens/video_details_screen/video_details_comments.dart b/lib/src/screens/video_details_screen/video_details_comments.dart index 088cac9b..88576f5d 100644 --- a/lib/src/screens/video_details_screen/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/video_details_comments.dart @@ -26,8 +26,8 @@ class _VideoDetailsCommentsState extends State { var client = http.Client(); var body = hiveCommentRequestToJson(HiveCommentRequest.from([author, permlink])); - var response = - await client.post(Uri.parse('https://${widget.rpc}'), body: body); + var rpc = 'https://${widget.rpc}'; + var response = await client.post(Uri.parse(rpc), body: body); if (response.statusCode == 200) { var hiveCommentsResponse = hiveCommentsFromString(response.body); var comments = hiveCommentsResponse.result; diff --git a/lib/src/screens/video_details_screen/video_details_info.dart b/lib/src/screens/video_details_screen/video_details_info.dart index 55e3e752..d7521cd8 100644 --- a/lib/src/screens/video_details_screen/video_details_info.dart +++ b/lib/src/screens/video_details_screen/video_details_info.dart @@ -1,3 +1,4 @@ +import 'package:acela/src/models/stories/stories_feed_response.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:flutter/material.dart'; @@ -6,20 +7,30 @@ import 'package:timeago/timeago.dart' as timeago; import 'package:url_launcher/url_launcher.dart'; class VideoDetailsInfoWidget extends StatelessWidget { - const VideoDetailsInfoWidget({Key? key, required this.details}) - : super(key: key); - final VideoDetails details; + const VideoDetailsInfoWidget({ + Key? key, + required this.details, + required this.item, + }) : super(key: key); + final VideoDetails? details; + final StoriesFeedResponseItem? item; Widget header(BuildContext context) { String string = - "📆 ${timeago.format(DateTime.parse(details.created))} · ▶ ${details.views} views · 👥 ${details.community}"; + "📆 ${timeago.format(DateTime.parse(details?.created ?? item!.created))} · ▶ ${details?.views ?? item!.views} views"; + if (details != null) { + string += " · 👥 ${details!.community}"; + } return Container( margin: const EdgeInsets.only(left: 10, right: 10, top: 10), child: Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(details.title, style: Theme.of(context).textTheme.bodyLarge), + Text( + details?.title ?? item?.title ?? "", + style: Theme.of(context).textTheme.bodyLarge, + ), const SizedBox(height: 3), Text(string, style: Theme.of(context).textTheme.bodySmall), ], @@ -42,14 +53,16 @@ class VideoDetailsInfoWidget extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(details.title), + title: Text(details?.title ?? item?.title ?? ""), ), body: SafeArea( child: Stack( children: [ Container( margin: const EdgeInsets.only(top: 70), - child: descriptionMarkDown(details.description), + child: descriptionMarkDown( + details?.description ?? item?.description ?? "not available", + ), ), header(context), ], diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index cfc0d74a..2b8ad1ef 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -198,7 +198,10 @@ class _VideoDetailsScreenState extends State { IconButton( onPressed: () { var route = MaterialPageRoute(builder: (context) { - return VideoDetailsInfoWidget(details: details); + return VideoDetailsInfoWidget( + details: details, + item: null, + ); }); Navigator.of(context).push(route); }, From 7b3d09dda209961ccdd394ead5a619919a153489 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 22 Dec 2022 17:36:47 +0530 Subject: [PATCH 145/466] hive keychain based login works on iOS --- .flutter-plugins-dependencies | 2 +- assets/hive-keychain-image.png | Bin 0 -> 48348 bytes ios/Runner.xcodeproj/project.pbxproj | 16 +- ios/Runner/AcelaWebViewController.swift | 23 + ios/Runner/AppDelegate.swift | 2 + ios/Runner/Bridges/Auth/HASBridge.swift | 72 ++ .../Auth/ValidateHiveKeyResponse.swift | 12 +- ios/Runner/Info.plist | 2 +- ios/Runner/public/index.html | 631 +++++++++++++----- lib/main.dart | 6 + .../models/login/login_bridge_response.dart | 4 + .../models/user_stream/hive_user_stream.dart | 4 + lib/src/screens/login/login_screen.dart | 124 +++- .../account_settings_screen.dart | 4 + .../screens/my_account/my_account_screen.dart | 4 + lib/src/screens/settings/settings_screen.dart | 6 + lib/src/utils/communicator.dart | 4 + pubspec.yaml | 3 +- 18 files changed, 703 insertions(+), 216 deletions(-) create mode 100644 assets/hive-keychain-image.png create mode 100644 ios/Runner/Bridges/Auth/HASBridge.swift diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index f0abc051..a3d80ffe 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-18 22:58:47.231618","version":"3.7.0-1.1.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-22 17:36:44.311533","version":"3.7.0-1.2.pre"} \ No newline at end of file diff --git a/assets/hive-keychain-image.png b/assets/hive-keychain-image.png new file mode 100644 index 0000000000000000000000000000000000000000..2efe39524d57aa660f4975b1217bec7d348c3a94 GIT binary patch literal 48348 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 FV1g-q;u-(| literal 0 HcmV?d00001 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index ece97fea..85e863d6 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 1B6A509E281E219E00480755 /* public in Resources */ = {isa = PBXBuildFile; fileRef = 1B6A509D281E219E00480755 /* public */; }; 1B6A50A1281E290300480755 /* AuthBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6A50A0281E290300480755 /* AuthBridge.swift */; }; 1B6A50A4281F5AEF00480755 /* ValidateHiveKeyResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6A50A3281F5AEF00480755 /* ValidateHiveKeyResponse.swift */; }; + 1B951A4D2954716D00BBA4CF /* HASBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B951A4C2954716D00BBA4CF /* HASBridge.swift */; }; 1BBABA1B27E2F977000ABB58 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1BBABA1A27E2F977000ABB58 /* GoogleService-Info.plist */; }; 23F3017383FF2D45A9FFE1B2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 900CC1210BBABA2901A394FB /* Pods_Runner.framework */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; @@ -45,6 +46,7 @@ 1B6A509D281E219E00480755 /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; }; 1B6A50A0281E290300480755 /* AuthBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthBridge.swift; sourceTree = ""; }; 1B6A50A3281F5AEF00480755 /* ValidateHiveKeyResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidateHiveKeyResponse.swift; sourceTree = ""; }; + 1B951A4C2954716D00BBA4CF /* HASBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HASBridge.swift; sourceTree = ""; }; 1BBABA1A27E2F977000ABB58 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 1BFFAA0B285824800093D01C /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 3655DA9EF6F21F87FCBD0D8C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; @@ -104,6 +106,7 @@ 1B6A50A2281F5AE500480755 /* Auth */ = { isa = PBXGroup; children = ( + 1B951A4C2954716D00BBA4CF /* HASBridge.swift */, 1B6A50A0281E290300480755 /* AuthBridge.swift */, 1B6A50A3281F5AEF00480755 /* ValidateHiveKeyResponse.swift */, ); @@ -333,6 +336,7 @@ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1B24F3CC282EC1F600256625 /* VideoEncoderSizes.swift in Sources */, 1B6A5097281E206800480755 /* AcelaWebViewController.swift in Sources */, + 1B951A4D2954716D00BBA4CF /* HASBridge.swift in Sources */, 1B6A50A4281F5AEF00480755 /* ValidateHiveKeyResponse.swift in Sources */, 1B6A50A1281E290300480755 /* AuthBridge.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, @@ -392,7 +396,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 52; + CURRENT_PROJECT_VERSION = 53; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -426,7 +430,7 @@ CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 52; + CURRENT_PROJECT_VERSION = 53; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -475,7 +479,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 52; + CURRENT_PROJECT_VERSION = 53; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -534,7 +538,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 52; + CURRENT_PROJECT_VERSION = 53; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -570,7 +574,7 @@ CODE_SIGN_IDENTITY = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 52; + CURRENT_PROJECT_VERSION = 53; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -600,7 +604,7 @@ CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 52; + CURRENT_PROJECT_VERSION = 53; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index 5e39291a..f02a7cfd 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -18,6 +18,9 @@ class AcelaWebViewController: UIViewController { var decryptTokenHandler: ((String) -> Void)? var postVideoHandler: ((String) -> Void)? + var getRedirectUriHandler: ((String) -> Void)? = nil + var hiveUserInfoHandler: ((String) -> Void)? = nil + override func viewDidLoad() { super.viewDidLoad() config.userContentController.add(self, name: acela) @@ -76,6 +79,16 @@ class AcelaWebViewController: UIViewController { self.webView?.evaluateJavaScript("newPostVideo('\(thumbnail)','\(video_v2)', '\(description)', '\(title)', '\(tags)', '\(username)', '\(permlink)', \(duration), \(size), '\(originalFilename)', 'en', \(firstUpload ? "true" : "false"), '\(bene)', '\(beneW)', '\(postingKey)', '\(community)');") } } + + func getRedirectUri(_ username: String, handler: @escaping (String) -> Void) { + getRedirectUriHandler = handler + webView?.evaluateJavaScript("getRedirectUri('\(username)');") + } + + func getUserInfo(_ handler: @escaping (String) -> Void) { + hiveUserInfoHandler = handler + webView?.evaluateJavaScript("getUserInfo();") + } } extension AcelaWebViewController: WKNavigationDelegate { @@ -124,6 +137,16 @@ extension AcelaWebViewController: WKScriptMessageHandler { debugPrint("Is it valid? \(isValid ? "TRUE" : "FALSE")") debugPrint("Error is \(error)") postVideoHandler?(response) + case "hiveAuthUserInfo": + guard + let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) + else { return } + hiveUserInfoHandler?(response) + case "getRedirectUri": + guard + let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) + else { return } + getRedirectUriHandler?(response) default: debugPrint("Do nothing here.") } } diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 18e60fca..fef14a55 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -7,6 +7,7 @@ import AVKit var acela: AcelaWebViewController? let authBridge = AuthBridge() let encoderBridge = EncoderBridge() + let hasBridge = HASBridge() override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? @@ -18,6 +19,7 @@ import AVKit let controller : FlutterViewController = window?.rootViewController as! FlutterViewController authBridge.initiate(controller: controller, window: window, acela: acela) encoderBridge.initiate(controller: controller, window: window, acela: acela) + hasBridge.initiate(controller: controller, window: window, acela: acela) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) diff --git a/ios/Runner/Bridges/Auth/HASBridge.swift b/ios/Runner/Bridges/Auth/HASBridge.swift new file mode 100644 index 00000000..0b13f3f5 --- /dev/null +++ b/ios/Runner/Bridges/Auth/HASBridge.swift @@ -0,0 +1,72 @@ +// +// Bridge.swift +// Runner +// +// Created by Sagar on 24/11/22. +// + +import Foundation +import UIKit +import Flutter + +class HASBridge { + var window: UIWindow? + var acela: AcelaWebViewController? + + func initiate( + controller: FlutterViewController, + window: UIWindow?, + acela: AcelaWebViewController? + ) { + self.window = window + self.acela = acela + let authChannel = FlutterMethodChannel( + name: "blog.hive.auth/bridge", + binaryMessenger: controller.binaryMessenger + ) + + authChannel.setMethodCallHandler({ + [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + // Note: this method is invoked on the UI thread. + switch (call.method) { + case "getRedirectUri": + guard + let arguments = call.arguments as? NSDictionary, + let username = arguments ["username"] as? String + else { + result(FlutterMethodNotImplemented) + return + } + self?.getRedirectUri(username: username, result: result) + case "getUserInfo": + self?.getUserInfo(result: result) + default: + result(FlutterMethodNotImplemented) + } + }) + } + + private func getUserInfo(result: @escaping FlutterResult) { + guard let acela = acela else { + result(FlutterError(code: "ERROR", + message: "Error setting up Hive", + details: nil)) + return + } + acela.getUserInfo { string in + result(string) + } + } + + private func getRedirectUri(username: String, result: @escaping FlutterResult) { + guard let acela = acela else { + result(FlutterError(code: "ERROR", + message: "Error setting up Hive", + details: nil)) + return + } + acela.getRedirectUri(username) { string in + result(string) + } + } +} diff --git a/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift b/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift index b6ceed0d..bc4364fc 100644 --- a/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift +++ b/ios/Runner/Bridges/Auth/ValidateHiveKeyResponse.swift @@ -11,6 +11,7 @@ struct ValidateHiveKeyResponse: Codable { let valid: Bool let accountName: String? let error: String + let data: String? static func jsonStringFrom(dict: [String: AnyObject]) -> String? { guard @@ -20,10 +21,15 @@ struct ValidateHiveKeyResponse: Codable { let response = ValidateHiveKeyResponse( valid: isValid, accountName: dict["accountName"] as? String, - error: error + error: error, + data: dict["data"] as? String ) - guard let data = try? JSONEncoder().encode(response) else { return nil } - guard let dataString = String(data: data, encoding: .utf8) else { return nil } + guard + let data = try? JSONEncoder().encode(response) + else { return nil } + guard + let dataString = String(data: data, encoding: .utf8) + else { return nil } return dataString } } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 353fa3c1..bc447252 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -23,7 +23,7 @@ CFBundleSignature ???? CFBundleVersion - 52 + 53 LSRequiresIPhoneOS LSSupportsOpeningDocumentsInPlace diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index b622901c..18a1565f 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -10,73 +10,80 @@ + + + + diff --git a/lib/main.dart b/lib/main.dart index 78aab819..d3556225 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -68,6 +68,8 @@ class _MyAppState extends State { value: server.hiveUserData, initialData: HiveUserData( resolution: '480p', + hasExpiry: null, + hasId: null, cookie: null, postingKey: null, username: null, @@ -138,12 +140,16 @@ class _MyAppState extends State { String? username = await storage.read(key: 'username'); String? postingKey = await storage.read(key: 'postingKey'); String? cookie = await storage.read(key: 'cookie'); + String? hasId = await storage.read(key: 'hasId'); + String? hasExpiry = await storage.read(key: 'hasExpiry'); String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( HiveUserData( username: username, postingKey: postingKey, + hasId: hasId, + hasExpiry: hasExpiry, cookie: cookie, resolution: resolution, rpc: rpc, diff --git a/lib/src/models/login/login_bridge_response.dart b/lib/src/models/login/login_bridge_response.dart index 213d17e8..2c96b27c 100644 --- a/lib/src/models/login/login_bridge_response.dart +++ b/lib/src/models/login/login_bridge_response.dart @@ -6,11 +6,13 @@ class LoginBridgeResponse { final bool valid; final String? accountName; final String error; + final String? data; LoginBridgeResponse({ required this.valid, required this.accountName, required this.error, + required this.data, }); factory LoginBridgeResponse.fromJson(Map? json) => @@ -18,6 +20,7 @@ class LoginBridgeResponse { valid: asBool(json, 'valid'), accountName: asString(json, 'accountName'), error: asString(json, 'error'), + data: asString(json, 'data'), ); factory LoginBridgeResponse.fromJsonString(String jsonString) => @@ -27,5 +30,6 @@ class LoginBridgeResponse { 'valid': valid, 'accountName': accountName, 'error': error, + 'data': data, }; } diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index 55745dac..f8cd72c3 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -1,6 +1,8 @@ class HiveUserData { String? username; String? postingKey; + String? hasId; + String? hasExpiry; String? cookie; String resolution; String rpc; @@ -8,6 +10,8 @@ class HiveUserData { HiveUserData({ required this.username, required this.postingKey, + required this.hasId, + required this.hasExpiry, required this.cookie, required this.resolution, required this.rpc, diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index ffc628da..6f84bef9 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -1,4 +1,7 @@ +import 'dart:developer'; + import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/crypto_manager.dart'; @@ -6,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({Key? key}) : super(key: key); @@ -42,6 +46,8 @@ class _LoginScreenState extends State { HiveUserData( username: username, postingKey: postingKey, + hasId: null, + hasExpiry: null, cookie: null, resolution: resolution, rpc: rpc, @@ -71,40 +77,102 @@ class _LoginScreenState extends State { ScaffoldMessenger.of(context).showSnackBar(snackBar); } + Widget _hiveUserName() { + return TextField( + decoration: InputDecoration( + icon: const Icon(Icons.person), + label: const Text('Hive Username'), + hintText: 'Enter Hive username here', + ), + autocorrect: false, + onChanged: (value) { + setState(() { + username = value; + }); + }, + enabled: isLoading ? false : true, + ); + } + + Widget _hivePostingKey() { + return TextField( + decoration: InputDecoration( + icon: const Icon(Icons.key), + label: const Text('Hive Posting Key'), + hintText: 'Copy & paste posting key here', + ), + obscureText: true, + onChanged: (value) { + setState(() { + postingKey = value; + }); + }, + enabled: isLoading ? false : true, + ); + } + + Widget _hasButton() { + return ElevatedButton( + onPressed: () async { + if (username.isNotEmpty) { + var platform = const MethodChannel('blog.hive.auth/bridge'); + var values = await platform.invokeMethod('getUserInfo'); + var valuesResponse = LoginBridgeResponse.fromJsonString(values); + if (valuesResponse.data == "undefined,undefined") { + final String authStr = + await platform.invokeMethod('getRedirectUri', { + 'username': username, + }); + log('Hive auth string is $authStr'); + var bridgeResponse = LoginBridgeResponse.fromJsonString(authStr); + if (bridgeResponse.data != null) { + var url = Uri.parse(bridgeResponse.data!); + launchUrl(url); + } + } else { + debugPrint("Successful login"); + String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + var hasId = valuesResponse.data!.split(",")[0]; + var hasExpiry = valuesResponse.data!.split(",")[1]; + await storage.write(key: 'hasId', value: hasId); + await storage.write(key: 'hasExpiry', value: hasExpiry); + await storage.delete(key: 'cookie'); + server.updateHiveUserData( + HiveUserData( + username: username, + postingKey: null, + hasId: hasId, + hasExpiry: hasExpiry, + cookie: null, + resolution: resolution, + rpc: rpc, + ), + ); + Navigator.of(context).pop(); + setState(() { + isLoading = false; + }); + } + } else { + showError('Please enter hive username'); + } + }, + child: Image.asset('assets/hive-keychain-image.png'), + ); + } + Widget _loginForm(HiveUserData appData) { return Container( margin: EdgeInsets.all(10), child: Column( children: [ - TextField( - decoration: InputDecoration( - icon: const Icon(Icons.person), - label: const Text('Hive Username'), - hintText: 'Enter Hive username here', - ), - autocorrect: false, - onChanged: (value) { - setState(() { - username = value; - }); - }, - enabled: isLoading ? false : true, - ), + _hiveUserName(), SizedBox(height: 20), - TextField( - decoration: InputDecoration( - icon: const Icon(Icons.key), - label: const Text('Hive Posting Key'), - hintText: 'Copy & paste posting key here', - ), - obscureText: true, - onChanged: (value) { - setState(() { - postingKey = value; - }); - }, - enabled: isLoading ? false : true, - ), + _hasButton(), + SizedBox(height: 50), + const Text('- OR -'), + _hivePostingKey(), SizedBox(height: 20), isLoading ? CircularProgressIndicator() diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index c37a3657..95614160 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -17,12 +17,16 @@ class _AccountSettingsScreenState extends State { await storage.delete(key: 'username'); await storage.delete(key: 'postingKey'); await storage.delete(key: 'cookie'); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( HiveUserData( username: null, postingKey: null, + hasId: null, + hasExpiry: null, cookie: null, resolution: resolution, rpc: rpc, diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index a060bd9d..63a6e43a 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -28,12 +28,16 @@ class _MyAccountScreenState extends State { await storage.delete(key: 'username'); await storage.delete(key: 'postingKey'); await storage.delete(key: 'cookie'); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( HiveUserData( username: null, postingKey: null, + hasId: null, + hasExpiry: null, cookie: null, resolution: resolution, rpc: rpc, diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index 594af285..7d3927bb 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -45,6 +45,8 @@ class _SettingsScreenState extends State { await storage.write(key: 'resolution', value: optionName); String? username = await storage.read(key: 'username'); String? postingKey = await storage.read(key: 'postingKey'); + String? hasId = await storage.read(key: 'hasId'); + String? hasExpiry = await storage.read(key: 'hasExpiry'); String? cookie = await storage.read(key: 'cookie'); String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( @@ -53,6 +55,8 @@ class _SettingsScreenState extends State { postingKey: postingKey, cookie: cookie, resolution: optionName, + hasId: hasId, + hasExpiry: hasExpiry, rpc: rpc, ), ); @@ -107,6 +111,8 @@ class _SettingsScreenState extends State { HiveUserData( username: user.username, postingKey: user.postingKey, + hasId: user.hasId, + hasExpiry: user.hasExpiry, cookie: user.cookie, resolution: user.resolution, rpc: serverUrl, diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 242b49cb..15514b7e 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -218,6 +218,8 @@ class Communicator { var newData = HiveUserData( username: user.username, postingKey: user.postingKey, + hasId: user.hasId, + hasExpiry: user.hasExpiry, cookie: cookie, resolution: resolution, rpc: rpc, @@ -250,6 +252,8 @@ class Communicator { var newData = HiveUserData( username: user.username, postingKey: user.postingKey, + hasId: user.hasId, + hasExpiry: user.hasExpiry, cookie: null, resolution: resolution, rpc: rpc, diff --git a/pubspec.yaml b/pubspec.yaml index 05f77fda..33f1c6ce 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.3+46 +version: 1.0.3+47 environment: sdk: ">=2.15.1 <3.0.0" @@ -100,6 +100,7 @@ flutter: - assets/branding/three_speak_logo.png - assets/branding/three_speak_icon.png - assets/branding/three_shorts_icon.png + - assets/hive-keychain-image.png - .env # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg From 90cfbe08ab1465994c20593fdca76516bed47fde Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 22 Dec 2022 19:44:52 +0530 Subject: [PATCH 146/466] app restart login issue fixed --- .flutter-plugins-dependencies | 2 +- lib/src/screens/login/login_screen.dart | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index a3d80ffe..daba956a 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-22 17:36:44.311533","version":"3.7.0-1.2.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-22 17:49:55.179255","version":"3.7.0-1.2.pre"} \ No newline at end of file diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 6f84bef9..9779e219 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -135,6 +135,7 @@ class _LoginScreenState extends State { String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; var hasId = valuesResponse.data!.split(",")[0]; var hasExpiry = valuesResponse.data!.split(",")[1]; + await storage.write(key: 'username', value: username); await storage.write(key: 'hasId', value: hasId); await storage.write(key: 'hasExpiry', value: hasExpiry); await storage.delete(key: 'cookie'); From 8522b2786697ea90ddd375865b6a69ba067ffb1b Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 3 Jan 2023 10:47:37 +0530 Subject: [PATCH 147/466] IPFS Hash --- .flutter-plugins-dependencies | 2 +- android/app/src/main/assets/index.html | 3 +- .../kotlin/com/example/acela/MainActivity.kt | 5 +- assets/ipfs-logo.png | Bin 0 -> 33672 bytes ios/Runner/AcelaWebViewController.swift | 3 +- ios/Runner/Bridges/Auth/AuthBridge.swift | 4 +- ios/Runner/public/index.html | 4 +- .../community_details_screen.dart | 1 + .../home_screen/home_screen_widgets.dart | 1 + .../update_video/video_details_info.dart | 9 +++- lib/src/screens/search/search_screen.dart | 1 + .../user_channel_videos.dart | 1 + .../video_details_screen.dart | 21 +++++++- lib/src/widgets/list_tile_video.dart | 49 +++++++++++------- pubspec.yaml | 1 + 15 files changed, 78 insertions(+), 27 deletions(-) create mode 100644 assets/ipfs-logo.png diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index daba956a..b9a9f94d 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2022-12-22 17:49:55.179255","version":"3.7.0-1.2.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-03 10:45:52.974822","version":"3.7.0-1.2.pre"} \ No newline at end of file diff --git a/android/app/src/main/assets/index.html b/android/app/src/main/assets/index.html index a2f3df44..856c590d 100644 --- a/android/app/src/main/assets/index.html +++ b/android/app/src/main/assets/index.html @@ -177,9 +177,10 @@ }]; } - function newPostVideo(thumbnail,videoV2,dDescription,dTitle,tags,author,permlink,duration,size,file,language,firstUpload,benes,beneWeights,postingKey,community) { + function newPostVideo(thumbnail,videoV2,dDescription,dTitle,tags,author,permlink,duration,size,file,language,firstUpload,benes,beneWeights,postingKey,community,ipfsHash) { let description = atob(dDescription); description = decodeURIComponent(escape(description)); + description = `${description}\nIPFS HASH: ${ipfsHash}`; let title = atob(dTitle); title = decodeURIComponent(escape(title)); let jsonMetaData = buildJSONMetadata(thumbnail,videoV2,description,title,tags,author,permlink,duration,size,file,language,firstUpload); diff --git a/android/app/src/main/kotlin/com/example/acela/MainActivity.kt b/android/app/src/main/kotlin/com/example/acela/MainActivity.kt index 2865283c..fdcf23a9 100644 --- a/android/app/src/main/kotlin/com/example/acela/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/acela/MainActivity.kt @@ -70,6 +70,7 @@ class MainActivity: FlutterActivity() { val bene = call.argument("bene") val beneW = call.argument("beneW") val community = call.argument("community") + val ipfsHash = call.argument("ipfsHash") val data = call.argument("data") if (call.method == "validate" && username != null && postingKey != null) { @@ -82,8 +83,8 @@ class MainActivity: FlutterActivity() { } else if (call.method == "newPostVideo" && thumbnail != null && video_v2 != null && description != null && title != null && tags != null && username != null && permlink != null && duration != null && size != null && originalFilename != null - && firstUpload != null && bene != null && beneW != null && community != null) { - webView?.evaluateJavascript("newPostVideo('$thumbnail','$video_v2', '$description', '$title', '$tags', '$username', '$permlink', $duration, $size, '$originalFilename', 'en', $firstUpload, '$bene', '$beneW', '$postingKey', '$community');", null) + && firstUpload != null && bene != null && beneW != null && community != null && ipfsHash != null) { + webView?.evaluateJavascript("newPostVideo('$thumbnail','$video_v2', '$description', '$title', '$tags', '$username', '$permlink', $duration, $size, '$originalFilename', 'en', $firstUpload, '$bene', '$beneW', '$postingKey', '$community', '$ipfsHash');", null) } } } diff --git a/assets/ipfs-logo.png b/assets/ipfs-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5d26eb26812f3befbcf557e99a849450d08adbe5 GIT binary patch literal 33672 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 Void ) { postVideoHandler = handler OperationQueue.main.addOperation { - self.webView?.evaluateJavaScript("newPostVideo('\(thumbnail)','\(video_v2)', '\(description)', '\(title)', '\(tags)', '\(username)', '\(permlink)', \(duration), \(size), '\(originalFilename)', 'en', \(firstUpload ? "true" : "false"), '\(bene)', '\(beneW)', '\(postingKey)', '\(community)');") + self.webView?.evaluateJavaScript("newPostVideo('\(thumbnail)','\(video_v2)', '\(description)', '\(title)', '\(tags)', '\(username)', '\(permlink)', \(duration), \(size), '\(originalFilename)', 'en', \(firstUpload ? "true" : "false"), '\(bene)', '\(beneW)', '\(postingKey)', '\(community)', '\(ipfsHash)');") } } diff --git a/ios/Runner/Bridges/Auth/AuthBridge.swift b/ios/Runner/Bridges/Auth/AuthBridge.swift index 9b6371d2..cc681b08 100644 --- a/ios/Runner/Bridges/Auth/AuthBridge.swift +++ b/ios/Runner/Bridges/Auth/AuthBridge.swift @@ -62,6 +62,7 @@ class AuthBridge { let beneW = arguments["beneW"] as? String, let postingKey = arguments["postingKey"] as? String, let community = arguments["community"] as? String, + let ipfsHash = arguments["ipfsHash"] as? String, let acela = acela else { result(FlutterMethodNotImplemented) @@ -82,7 +83,8 @@ class AuthBridge { bene: bene, beneW: beneW, postingKey: postingKey, - community: community + community: community, + ipfsHash: ipfsHash ) { response in result(response) } diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index 18a1565f..e427f2dc 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -223,10 +223,12 @@ benes, beneWeights, postingKey, - community + community, + ipfsHash ) { let description = atob(dDescription); description = decodeURIComponent(escape(description)); + description = `${description}\nIPFS HASH: ${ipfsHash}`; let title = atob(dTitle); title = decodeURIComponent(escape(title)); let jsonMetaData = buildJSONMetadata( diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index aa2086eb..4404b200 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -114,6 +114,7 @@ class _CommunityDetailScreenState extends State user: item.author, permlink: item.permlink, shouldResize: true, + isIpfs: item.isIpfs, ); } diff --git a/lib/src/screens/home_screen/home_screen_widgets.dart b/lib/src/screens/home_screen/home_screen_widgets.dart index ca78b332..c4e3c4c9 100644 --- a/lib/src/screens/home_screen/home_screen_widgets.dart +++ b/lib/src/screens/home_screen/home_screen_widgets.dart @@ -36,6 +36,7 @@ class HomeScreenWidgets { user: item.author, permlink: item.permlink, shouldResize: true, + isIpfs: item.playUrl.contains('ipfs'), ); } diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index 54c917a2..4a58b731 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -128,6 +128,12 @@ class _VideoDetailsInfoState extends State { const platform = MethodChannel('com.example.acela/auth'); var title = base64.encode(utf8.encode(widget.title)); var description = base64.encode(utf8.encode(widget.subtitle)); + var ipfsHash = ""; + if (widget.item.playUrl.contains('ipfs')) { + ipfsHash = widget.item.playUrl + .replaceAll("https://ipfs-3speak.b-cdn.net/ipfs/", "") + .replaceAll("/manifest.m3u8", "replace"); + } final String response = await platform.invokeMethod('newPostVideo', { 'thumbnail': v.thumbnailValue, 'video_v2': v.videoValue, @@ -144,11 +150,12 @@ class _VideoDetailsInfoState extends State { 'beneW': v.benes[1], 'postingKey': user.postingKey, 'community': widget.item.isReel ? 'hive-151961' : selectedCommunity, + 'ipfsHash': ipfsHash, }); log('Response from platform $response'); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); if (bridgeResponse.error == "success") { - await Future.delayed(const Duration(seconds: 3), () {}); + await Future.delayed(const Duration(seconds: 5), () {}); await Communicator().updatePublishState(user, v.id); setState(() { isCompleting = false; diff --git a/lib/src/screens/search/search_screen.dart b/lib/src/screens/search/search_screen.dart index cce8cc5c..2c1526eb 100644 --- a/lib/src/screens/search/search_screen.dart +++ b/lib/src/screens/search/search_screen.dart @@ -158,6 +158,7 @@ class _SearchScreenState extends State { user: item.author, permlink: item.permlink, shouldResize: false, + isIpfs: false, ), onTap: () { var vm = diff --git a/lib/src/screens/user_channel_screen/user_channel_videos.dart b/lib/src/screens/user_channel_screen/user_channel_videos.dart index e719a868..5b6bcccc 100644 --- a/lib/src/screens/user_channel_screen/user_channel_videos.dart +++ b/lib/src/screens/user_channel_screen/user_channel_videos.dart @@ -145,6 +145,7 @@ class UserChannelVideosState extends State user: item.author, permlink: item.permlink, shouldResize: true, + isIpfs: item.playUrl.contains('ipfs'), ); } diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 2b8ad1ef..960d9ad1 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -20,6 +20,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:http/http.dart' as http; import 'package:provider/provider.dart'; +import 'package:share_plus/share_plus.dart'; import 'package:timeago/timeago.dart' as timeago; import 'package:url_launcher/url_launcher.dart'; @@ -206,7 +207,24 @@ class _VideoDetailsScreenState extends State { Navigator.of(context).push(route); }, icon: const Icon(Icons.fullscreen), - ) + ), + details.playUrl.contains('ipfs') + ? IconButton( + onPressed: () { + var ipfsHash = details.playUrl + .replaceAll( + "https://ipfs-3speak.b-cdn.net/ipfs/", "") + .replaceAll("/manifest.m3u8", "replace"); + Share.share( + "Copy this IPFS Hash & Pin it on your system - $ipfsHash"); + }, + icon: Image.asset( + 'assets/ipfs-logo.png', + width: 20, + height: 20, + ), + ) + : Container(), ], ), ) @@ -420,6 +438,7 @@ class _VideoDetailsScreenState extends State { user: item.owner, permlink: item.mediaid, shouldResize: false, + isIpfs: false, ); } diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index bf0a6eba..eaea8746 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -22,6 +22,7 @@ class ListTileVideo extends StatefulWidget { required this.user, required this.permlink, required this.shouldResize, + required this.isIpfs, }) : super(key: key); final String placeholder; @@ -33,6 +34,7 @@ class ListTileVideo extends StatefulWidget { final String user; final String permlink; final bool shouldResize; + final bool isIpfs; @override State createState() => _ListTileVideoState(); @@ -117,24 +119,35 @@ class _ListTileVideoState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - height: 220, - width: MediaQuery.of(context).size.width, - child: FadeInImage.assetNetwork( - placeholder: widget.placeholder, - image: widget.shouldResize - ? server.resizedImage(widget.url) - : widget.url, - fit: BoxFit.fitWidth, - placeholderErrorBuilder: - (BuildContext context, Object error, StackTrace? stackTrace) { - return _errorIndicator(); - }, - imageErrorBuilder: - (BuildContext context, Object error, StackTrace? stackTrace) { - return _errorIndicator(); - }, - ), + Stack( + children: [ + SizedBox( + height: 220, + width: MediaQuery.of(context).size.width, + child: FadeInImage.assetNetwork( + placeholder: widget.placeholder, + image: widget.shouldResize + ? server.resizedImage(widget.url) + : widget.url, + fit: BoxFit.fitWidth, + placeholderErrorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return _errorIndicator(); + }, + imageErrorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return _errorIndicator(); + }, + ), + ), + widget.isIpfs + ? Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/ipfs-logo.png', + width: 30, height: 30), + ) + : Container(), + ], ), Container( padding: const EdgeInsets.all(3), diff --git a/pubspec.yaml b/pubspec.yaml index 33f1c6ce..7066563a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -101,6 +101,7 @@ flutter: - assets/branding/three_speak_icon.png - assets/branding/three_shorts_icon.png - assets/hive-keychain-image.png + - assets/ipfs-logo.png - .env # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg From 9e36ab40b61a22b8d6ec939f200c7bc360365135 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 3 Jan 2023 15:50:14 +0530 Subject: [PATCH 148/466] disabling HAS for now. --- .flutter-plugins-dependencies | 2 +- lib/src/screens/login/login_screen.dart | 6 +++--- .../screens/video_details_screen/video_details_screen.dart | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index b9a9f94d..40f227ff 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-03 10:45:52.974822","version":"3.7.0-1.2.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-03 10:54:06.867624","version":"3.7.0-1.2.pre"} \ No newline at end of file diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 9779e219..ea733adb 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -170,9 +170,9 @@ class _LoginScreenState extends State { children: [ _hiveUserName(), SizedBox(height: 20), - _hasButton(), - SizedBox(height: 50), - const Text('- OR -'), + // _hasButton(), + // SizedBox(height: 50), + // const Text('- OR -'), _hivePostingKey(), SizedBox(height: 20), isLoading diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 960d9ad1..7268d889 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -214,7 +214,7 @@ class _VideoDetailsScreenState extends State { var ipfsHash = details.playUrl .replaceAll( "https://ipfs-3speak.b-cdn.net/ipfs/", "") - .replaceAll("/manifest.m3u8", "replace"); + .replaceAll("/manifest.m3u8", ""); Share.share( "Copy this IPFS Hash & Pin it on your system - $ipfsHash"); }, From 6433ef0eb10b93fa9d48fccdbe3f25d150228b18 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 3 Jan 2023 17:15:16 +0530 Subject: [PATCH 149/466] version bump. --- .flutter-plugins-dependencies | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 40f227ff..acaf8226 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-03 10:54:06.867624","version":"3.7.0-1.2.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-03 17:14:48.259486","version":"3.7.0-1.2.pre"} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 7066563a..9d77e39f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.3+47 +version: 1.0.4+48 environment: sdk: ">=2.15.1 <3.0.0" From c960335bcb95782fde373d54e8f5043f1dd9287a Mon Sep 17 00:00:00 2001 From: Spidy123222 <64176728+Spidy123222@users.noreply.github.com> Date: Sun, 15 Jan 2023 14:43:34 -0800 Subject: [PATCH 150/466] Remove comma --- ios/app.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/app.json b/ios/app.json index 57decdda..f6026b31 100644 --- a/ios/app.json +++ b/ios/app.json @@ -23,7 +23,7 @@ "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/IMG_5652.PNG", "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/IMG_5653.PNG", "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/IMG_5654.PNG", - "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/IMG_5655.PNG", + "https://github.com/spknetwork/Android-App/releases/download/v1.0.3_48/IMG_5655.PNG" ], "beta": false } @@ -41,4 +41,4 @@ "notify": true } ] -} \ No newline at end of file +} From d4998852fb70be76376aa4775f087c5e2575952f Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 17 Jan 2023 00:07:09 +0530 Subject: [PATCH 151/466] Hive-keychain based login & video upload. --- .env | 3 ++- .flutter-plugins-dependencies | 2 +- ios/Runner.xcodeproj/project.pbxproj | 12 +++++------ ios/Runner/Info.plist | 2 +- lib/src/screens/login/login_screen.dart | 6 +++--- lib/src/utils/communicator.dart | 27 ++++++++++++++++--------- 6 files changed, 31 insertions(+), 21 deletions(-) diff --git a/.env b/.env index 8a267824..8faabfc0 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ -HIVE_SEARCHER_AUTH_KEY=QFS2JICIIZJLHEYGA4XOLRTAQQP0XLVC6B9GU0NQCLWAFNGL6JGZKPUECPL6 \ No newline at end of file +HIVE_SEARCHER_AUTH_KEY=QFS2JICIIZJLHEYGA4XOLRTAQQP0XLVC6B9GU0NQCLWAFNGL6JGZKPUECPL6 +MOBILE_CLIENT_PRIVATE_KEY=5Jcbm4343JEcymtxVYXKMihVj2NJwRTtaph5DBuCbs3vGyRWKa5 \ No newline at end of file diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index acaf8226..dac0db1b 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-03 17:14:48.259486","version":"3.7.0-1.2.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-16 23:24:49.319899","version":"3.7.0-1.4.pre"} \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 85e863d6..bbbb8ba4 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -396,7 +396,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 53; + CURRENT_PROJECT_VERSION = 54; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -430,7 +430,7 @@ CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 53; + CURRENT_PROJECT_VERSION = 54; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -479,7 +479,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 53; + CURRENT_PROJECT_VERSION = 54; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -538,7 +538,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 53; + CURRENT_PROJECT_VERSION = 54; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -574,7 +574,7 @@ CODE_SIGN_IDENTITY = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development: Sagar Rajeshkumar Kothari (8LMF7N99VQ)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 53; + CURRENT_PROJECT_VERSION = 54; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; @@ -604,7 +604,7 @@ CODE_SIGN_IDENTITY = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Sagar Rajeshkumar Kothari (58LRY57FMK)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 53; + CURRENT_PROJECT_VERSION = 54; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; FLUTTER_BUILD_NUMBER = 12; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index bc447252..be9c2008 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -23,7 +23,7 @@ CFBundleSignature ???? CFBundleVersion - 53 + 54 LSRequiresIPhoneOS LSSupportsOpeningDocumentsInPlace diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index ea733adb..9779e219 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -170,9 +170,9 @@ class _LoginScreenState extends State { children: [ _hiveUserName(), SizedBox(height: 20), - // _hasButton(), - // SizedBox(height: 50), - // const Text('- OR -'), + _hasButton(), + SizedBox(height: 50), + const Text('- OR -'), _hivePostingKey(), SizedBox(height: 20), isLoading diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 15514b7e..ea5b4c19 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -16,13 +16,14 @@ import 'package:acela/src/models/video_upload/video_upload_complete_request.dart import 'package:acela/src/models/video_upload/video_upload_login_response.dart'; import 'package:acela/src/models/video_upload/video_upload_prepare_response.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:http/http.dart' as http; class Communicator { // Production - static const tsServer = "https://studio.3speak.tv"; - static const fsServer = "https://uploads.3speak.tv/files"; + // static const tsServer = "https://studio.3speak.tv"; + // static const fsServer = "https://uploads.3speak.tv/files"; // Android // static const fsServer = "http://10.0.2.2:1080/files"; @@ -33,8 +34,8 @@ class Communicator { // static const fsServer = "http://localhost:1080/files"; // iOS Device - // static const tsServer = "http://192.168.1.8:13050"; - // static const fsServer = "http://192.168.1.8:1080/files"; + static const tsServer = "http://192.168.29.239:13050"; + static const fsServer = "http://192.168.29.239:1080/files"; // static const hiveApiUrl = 'api.hive.blog'; static const threeSpeakCDN = 'https://ipfs-3speak.b-cdn.net'; @@ -142,9 +143,13 @@ class Communicator { Future _getAccessToken( HiveUserData user, String encryptedToken) async { const platform = MethodChannel('com.example.acela/auth'); + var key = + user.postingKey == null && user.hasExpiry != null && user.hasId != null + ? dotenv.env['MOBILE_CLIENT_PRIVATE_KEY'] + : user.postingKey ?? ""; final String result = await platform.invokeMethod('encryptedToken', { 'username': user.username, - 'postingKey': user.postingKey, + 'postingKey': key, 'encryptedToken': encryptedToken, }); var memo = MemoResponse.fromJsonString(result); @@ -181,10 +186,14 @@ class Communicator { } Future getValidCookie(HiveUserData user) async { - var request = http.Request( - 'GET', - Uri.parse( - '${Communicator.tsServer}/mobile/login?username=${user.username}')); + var uri = '${Communicator.tsServer}/mobile/login?username=${user.username}'; + if (user.hasId != null && + user.hasExpiry != null && + user.postingKey == null) { + uri = + '${Communicator.tsServer}/mobile/login?username=${user.username}&client=mobile'; + } + var request = http.Request('GET', Uri.parse(uri)); if (user.cookie != null) { Map map = {"cookie": user.cookie!}; request.headers.addAll(map); From 836f54bd99dc47e8e123d23d95fb2ac4a1d1119f Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 22 Jan 2023 18:40:45 +0530 Subject: [PATCH 152/466] HiveKeychain based Auth is working. Hive Keychain based adding a post in progress. --- .flutter-plugins-dependencies | 2 +- ios/.DS_Store | Bin 8196 -> 8196 bytes ios/Runner/AcelaWebViewController.swift | 4 +- ios/Runner/Bridges/Auth/AuthBridge.swift | 6 +- ios/Runner/public/index.html | 86 ++++++---- lib/main.dart | 21 ++- .../models/user_stream/hive_user_stream.dart | 16 +- lib/src/screens/login/login_screen.dart | 17 +- .../account_settings_screen.dart | 4 +- .../screens/my_account/my_account_screen.dart | 4 +- .../update_video/video_details_info.dart | 11 +- lib/src/screens/settings/settings_screen.dart | 18 +- lib/src/utils/communicator.dart | 157 ++++++++---------- 13 files changed, 194 insertions(+), 152 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index dac0db1b..069c4e1d 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-16 23:24:49.319899","version":"3.7.0-1.4.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-22 18:36:21.554037","version":"3.7.0-1.4.pre"} \ No newline at end of file diff --git a/ios/.DS_Store b/ios/.DS_Store index 6582f2451af46718d27365d805e85eff74877060..cee497b415698b3642e3c4accc434b278d0bb226 100644 GIT binary patch delta 21 ccmZp1XmQwZM~K73&{Rjk#Ke5_6Cnj&08bhQiU0rr delta 21 ccmZp1XmQwZM~K7Jz(7aA$k1@}6Cnj&08X0*dH?_b diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index f5d32a1a..999f76eb 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -73,11 +73,13 @@ class AcelaWebViewController: UIViewController { postingKey: String, community: String, ipfsHash: String, + hasKey: String, + hasAuthkey: String, handler: @escaping (String) -> Void ) { postVideoHandler = handler OperationQueue.main.addOperation { - self.webView?.evaluateJavaScript("newPostVideo('\(thumbnail)','\(video_v2)', '\(description)', '\(title)', '\(tags)', '\(username)', '\(permlink)', \(duration), \(size), '\(originalFilename)', 'en', \(firstUpload ? "true" : "false"), '\(bene)', '\(beneW)', '\(postingKey)', '\(community)', '\(ipfsHash)');") + self.webView?.evaluateJavaScript("newPostVideo('\(thumbnail)','\(video_v2)', '\(description)', '\(title)', '\(tags)', '\(username)', '\(permlink)', \(duration), \(size), '\(originalFilename)', 'en', \(firstUpload ? "true" : "false"), '\(bene)', '\(beneW)', '\(postingKey)', '\(community)', '\(ipfsHash)', '\(hasKey)', '\(hasAuthkey)');") } } diff --git a/ios/Runner/Bridges/Auth/AuthBridge.swift b/ios/Runner/Bridges/Auth/AuthBridge.swift index cc681b08..d10e41ae 100644 --- a/ios/Runner/Bridges/Auth/AuthBridge.swift +++ b/ios/Runner/Bridges/Auth/AuthBridge.swift @@ -63,6 +63,8 @@ class AuthBridge { let postingKey = arguments["postingKey"] as? String, let community = arguments["community"] as? String, let ipfsHash = arguments["ipfsHash"] as? String, + let hasKey = arguments["hasKey"] as? String, + let hasAuthKey = arguments["hasAuthKey"] as? String, let acela = acela else { result(FlutterMethodNotImplemented) @@ -84,7 +86,9 @@ class AuthBridge { beneW: beneW, postingKey: postingKey, community: community, - ipfsHash: ipfsHash + ipfsHash: ipfsHash, + hasKey: hasKey, + hasAuthkey: hasAuthKey ) { response in result(response) } diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index e427f2dc..842b17cc 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -133,7 +133,7 @@ let escapedVideoTitle = customStringEscaping(title); return { tags: processTags(tags.split(",")), - app: "3speak/0.3.0", + app: "3speakMobileiOS/1.0.4-48", type: "3speak/video", image: [thumbnail], video: { @@ -224,7 +224,9 @@ beneWeights, postingKey, community, - ipfsHash + ipfsHash, + hasKey, + hasAuthKey, ) { let description = atob(dDescription); description = decodeURIComponent(escape(description)); @@ -338,36 +340,45 @@ operations.push(comment_options); operations.push(customJson); console.log(`operations are ${JSON.stringify(operations)}`); - async function tryPublish(operations, key) { - try { - return hive.broadcast.sendAsync( - { operations }, - { posting: key } - ); - } catch (e) { - return e; - } + if (hasKey !== null && hasToken !== null && hasKey.length > 0 && hasToken.length > 0) { + const sign_data = { + key_type: "posting", + ops: operations, + broadcast: true, + }; + const data = CryptoJS.AES.encrypt( + JSON.stringify(sign_data), + hasAuthKey + ).toString(); + const payload = { + cmd: "sign_req", + account: author, + token: hasKey, + data: data, + }; + ws.send(JSON.stringify(payload)); + } else { + tryPublish(operations, postingKey) + .then((result) => { + var newResult = { + type: "postVideo", + valid: true, + error: "success", + }; + window.webkit.messageHandlers.acela.postMessage(newResult); + //Android.postMessage(JSON.stringify(newResult)); + }) + .catch((error) => { + console.error(error); + var result = { + type: "postVideo", + valid: false, + error: error.message, + }; + window.webkit.messageHandlers.acela.postMessage(result); + //Android.postMessage(JSON.stringify(result)); + }); } - tryPublish(operations, postingKey) - .then((result) => { - var newResult = { - type: "postVideo", - valid: true, - error: "success", - }; - window.webkit.messageHandlers.acela.postMessage(newResult); - //Android.postMessage(JSON.stringify(newResult)); - }) - .catch((error) => { - console.error(error); - var result = { - type: "postVideo", - valid: false, - error: error.message, - }; - window.webkit.messageHandlers.acela.postMessage(result); - //Android.postMessage(JSON.stringify(result)); - }); }) .catch(function (err) { console.error(err); @@ -400,6 +411,7 @@ if ("WebSocket" in window) { // The browser support Websocket ws = new WebSocket(HAS_SERVER); + console.log(`Starting WebSocket with ${HAS_SERVER}`); ws.onopen = function () { // Web Socket is connected console.log("WebSocket connected"); @@ -456,7 +468,12 @@ alert(`transaction ${message.uuid} is waiting for approval`); break; case "sign_ack": - alert(`transaction ${message.uuid} approved`); + console.log(`transaction ${message.uuid} approved`); + replyToNative({ + type: "postVideo", + valid: true, + error: "success", + }); break; case "sign_nack": alert(`transaction ${message.uuid} has been declined`); @@ -471,6 +488,9 @@ ws.onclose = function () { console.log("WebSocket closed. Please reload the page..."); }; + ws.onerror = function (e) { + console.log(`WebSocket error. ${e}\nPlease reload the page...`); + }; } else { console.log("The browser doesn't support WebSocket"); } @@ -481,7 +501,7 @@ valid: true, username: username, error: "", - data: `${token},${expire}`, + data: `${token},${expire},${auth_key}`, }); } diff --git a/lib/main.dart b/lib/main.dart index d3556225..a216929d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; + // import 'package:firebase_core/firebase_core.dart'; // import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; @@ -14,6 +15,7 @@ class PushNotification { this.title, this.body, }); + String? title; String? body; } @@ -33,6 +35,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { late final Future _futureToLoadData; + // late final FirebaseMessaging _messaging; // Create storage @@ -68,8 +71,7 @@ class _MyAppState extends State { value: server.hiveUserData, initialData: HiveUserData( resolution: '480p', - hasExpiry: null, - hasId: null, + keychainData: null, cookie: null, postingKey: null, username: null, @@ -142,14 +144,25 @@ class _MyAppState extends State { String? cookie = await storage.read(key: 'cookie'); String? hasId = await storage.read(key: 'hasId'); String? hasExpiry = await storage.read(key: 'hasExpiry'); + String? hasAuthKey = await storage.read(key: 'hasAuthKey'); String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( HiveUserData( username: username, postingKey: postingKey, - hasId: hasId, - hasExpiry: hasExpiry, + keychainData: hasId != null && + hasId.isNotEmpty && + hasExpiry != null && + hasExpiry.isNotEmpty && + hasAuthKey != null && + hasAuthKey.isNotEmpty + ? HiveKeychainData( + hasAuthKey: hasAuthKey, + hasExpiry: hasExpiry, + hasId: hasId, + ) + : null, cookie: cookie, resolution: resolution, rpc: rpc, diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index f8cd72c3..cefdec8c 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -1,17 +1,25 @@ +class HiveKeychainData { + String hasId; + String hasExpiry; + String hasAuthKey; + HiveKeychainData({ + required this.hasId, + required this.hasExpiry, + required this.hasAuthKey, + }); +} class HiveUserData { String? username; String? postingKey; - String? hasId; - String? hasExpiry; String? cookie; + HiveKeychainData? keychainData; String resolution; String rpc; HiveUserData({ required this.username, required this.postingKey, - required this.hasId, - required this.hasExpiry, + required this.keychainData, required this.cookie, required this.resolution, required this.rpc, diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 9779e219..b62f5623 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -41,13 +41,15 @@ class _LoginScreenState extends State { String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; await storage.write(key: 'username', value: username); await storage.write(key: 'postingKey', value: postingKey); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); await storage.delete(key: 'cookie'); server.updateHiveUserData( HiveUserData( username: username, postingKey: postingKey, - hasId: null, - hasExpiry: null, + keychainData: null, cookie: null, resolution: resolution, rpc: rpc, @@ -118,7 +120,7 @@ class _LoginScreenState extends State { var platform = const MethodChannel('blog.hive.auth/bridge'); var values = await platform.invokeMethod('getUserInfo'); var valuesResponse = LoginBridgeResponse.fromJsonString(values); - if (valuesResponse.data == "undefined,undefined") { + if (valuesResponse.data?.startsWith("undefined,undefined") == true) { final String authStr = await platform.invokeMethod('getRedirectUri', { 'username': username, @@ -135,16 +137,21 @@ class _LoginScreenState extends State { String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; var hasId = valuesResponse.data!.split(",")[0]; var hasExpiry = valuesResponse.data!.split(",")[1]; + var hasAuthKey = valuesResponse.data!.split(",")[2]; await storage.write(key: 'username', value: username); await storage.write(key: 'hasId', value: hasId); await storage.write(key: 'hasExpiry', value: hasExpiry); + await storage.write(key: 'hasAuthKey', value: hasAuthKey); await storage.delete(key: 'cookie'); server.updateHiveUserData( HiveUserData( username: username, postingKey: null, - hasId: hasId, - hasExpiry: hasExpiry, + keychainData: HiveKeychainData( + hasId: hasId, + hasExpiry: hasExpiry, + hasAuthKey: hasAuthKey, + ), cookie: null, resolution: resolution, rpc: rpc, diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index 95614160..2eeb9fa9 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -19,14 +19,14 @@ class _AccountSettingsScreenState extends State { await storage.delete(key: 'cookie'); await storage.delete(key: 'hasId'); await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( HiveUserData( username: null, postingKey: null, - hasId: null, - hasExpiry: null, + keychainData: null, cookie: null, resolution: resolution, rpc: rpc, diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 63a6e43a..01df8c39 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -30,14 +30,14 @@ class _MyAccountScreenState extends State { await storage.delete(key: 'cookie'); await storage.delete(key: 'hasId'); await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( HiveUserData( username: null, postingKey: null, - hasId: null, - hasExpiry: null, + keychainData: null, cookie: null, resolution: resolution, rpc: rpc, diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index 4a58b731..48084df4 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -129,10 +129,11 @@ class _VideoDetailsInfoState extends State { var title = base64.encode(utf8.encode(widget.title)); var description = base64.encode(utf8.encode(widget.subtitle)); var ipfsHash = ""; - if (widget.item.playUrl.contains('ipfs')) { - ipfsHash = widget.item.playUrl + if (widget.item.video_v2.isNotEmpty) { + ipfsHash = widget.item.video_v2 .replaceAll("https://ipfs-3speak.b-cdn.net/ipfs/", "") - .replaceAll("/manifest.m3u8", "replace"); + .replaceAll("ipfs://", "") + .replaceAll("/manifest.m3u8", ""); } final String response = await platform.invokeMethod('newPostVideo', { 'thumbnail': v.thumbnailValue, @@ -148,9 +149,11 @@ class _VideoDetailsInfoState extends State { 'firstUpload': v.firstUpload, 'bene': v.benes[0], 'beneW': v.benes[1], - 'postingKey': user.postingKey, + 'postingKey': user.postingKey ?? '', 'community': widget.item.isReel ? 'hive-151961' : selectedCommunity, 'ipfsHash': ipfsHash, + 'hasKey': user.keychainData?.hasId ?? '', + 'hasAuthKey': user.keychainData?.hasAuthKey ?? '', }); log('Response from platform $response'); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index 7d3927bb..cd83f2c9 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -47,6 +47,7 @@ class _SettingsScreenState extends State { String? postingKey = await storage.read(key: 'postingKey'); String? hasId = await storage.read(key: 'hasId'); String? hasExpiry = await storage.read(key: 'hasExpiry'); + String? hasAuthKey = await storage.read(key: 'hasAuthKey'); String? cookie = await storage.read(key: 'cookie'); String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; server.updateHiveUserData( @@ -55,9 +56,19 @@ class _SettingsScreenState extends State { postingKey: postingKey, cookie: cookie, resolution: optionName, - hasId: hasId, - hasExpiry: hasExpiry, rpc: rpc, + keychainData: hasId != null && + hasId.isNotEmpty && + hasExpiry != null && + hasExpiry.isNotEmpty && + hasAuthKey != null && + hasAuthKey.isNotEmpty + ? HiveKeychainData( + hasAuthKey: hasAuthKey, + hasExpiry: hasExpiry, + hasId: hasId, + ) + : null, ), ); loadRes(); @@ -111,8 +122,7 @@ class _SettingsScreenState extends State { HiveUserData( username: user.username, postingKey: user.postingKey, - hasId: user.hasId, - hasExpiry: user.hasExpiry, + keychainData: user.keychainData, cookie: user.cookie, resolution: user.resolution, rpc: serverUrl, diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index ea5b4c19..a626d0ad 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -143,10 +143,9 @@ class Communicator { Future _getAccessToken( HiveUserData user, String encryptedToken) async { const platform = MethodChannel('com.example.acela/auth'); - var key = - user.postingKey == null && user.hasExpiry != null && user.hasId != null - ? dotenv.env['MOBILE_CLIENT_PRIVATE_KEY'] - : user.postingKey ?? ""; + var key = user.postingKey == null && user.keychainData != null + ? dotenv.env['MOBILE_CLIENT_PRIVATE_KEY'] + : user.postingKey ?? ""; final String result = await platform.invokeMethod('encryptedToken', { 'username': user.username, 'postingKey': key, @@ -161,35 +160,9 @@ class Communicator { return memo.decrypted.replaceFirst("#", ''); } - Future prepareVideo( - HiveUserData user, String videoInfo, String cookie) async { - var request = http.Request('POST', - Uri.parse('${Communicator.tsServer}/mobile/api/upload/prepare')); - request.body = videoInfo; - Map map = { - "cookie": cookie, - "Content-Type": "application/json" - }; - request.headers.addAll(map); - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - var string = await response.stream.bytesToString(); - log('Video upload prepare response is\n$string'); - return VideoUploadPrepareResponse.fromJsonString(string); - } else { - var string = await response.stream.bytesToString(); - var error = ErrorResponse.fromJsonString(string).error ?? - response.reasonPhrase.toString(); - log('Error from server is $error'); - throw error; - } - } - Future getValidCookie(HiveUserData user) async { var uri = '${Communicator.tsServer}/mobile/login?username=${user.username}'; - if (user.hasId != null && - user.hasExpiry != null && - user.postingKey == null) { + if (user.keychainData != null && user.postingKey == null) { uri = '${Communicator.tsServer}/mobile/login?username=${user.username}&client=mobile'; } @@ -198,82 +171,84 @@ class Communicator { Map map = {"cookie": user.cookie!}; request.headers.addAll(map); } - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - var string = await response.stream.bytesToString(); - var loginResponse = VideoUploadLoginResponse.fromJsonString(string); - if (loginResponse.error != null && loginResponse.error!.isNotEmpty) { - throw 'Error - ${loginResponse.error}'; - } else if (loginResponse.memo != null && loginResponse.memo!.isNotEmpty) { - var token = await _getAccessToken(user, loginResponse.memo!); - var url = - '${Communicator.tsServer}/mobile/login?username=${user.username}&access_token=$token'; - var request = http.Request('GET', Uri.parse(url)); - http.StreamedResponse response = await request.send(); + try { + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + var string = await response.stream.bytesToString(); + var loginResponse = VideoUploadLoginResponse.fromJsonString(string); + if (loginResponse.error != null && loginResponse.error!.isNotEmpty) { + throw 'Error - ${loginResponse.error}'; + } else if (loginResponse.memo != null && loginResponse.memo!.isNotEmpty) { + var token = await _getAccessToken(user, loginResponse.memo!); + var url = + '${Communicator.tsServer}/mobile/login?username=${user.username}&access_token=$token'; + var request = http.Request('GET', Uri.parse(url)); + http.StreamedResponse response = await request.send(); + var string = await response.stream.bytesToString(); + var tokenResponse = VideoUploadLoginResponse.fromJsonString(string); + var cookie = response.headers['set-cookie']; + if (tokenResponse.error != null && tokenResponse.error!.isNotEmpty) { + throw 'Error - ${tokenResponse.error}'; + } else if (tokenResponse.network == "hive" && + tokenResponse.banned != true && + tokenResponse.userId != null && + cookie != null && + cookie.isNotEmpty) { + const storage = FlutterSecureStorage(); + await storage.write(key: 'cookie', value: cookie); + String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + var newData = HiveUserData( + username: user.username, + postingKey: user.postingKey, + keychainData: user.keychainData, + cookie: cookie, + resolution: resolution, + rpc: rpc, + ); + server.updateHiveUserData(newData); + return cookie; + } else { + log('This should never happen. No error, no user info. How?'); + throw 'Something went wrong.'; + } + } else if (loginResponse.network == "hive" && + loginResponse.banned != true && + loginResponse.userId != null && + user.cookie != null) { + return user.cookie!; + } else { + log('This should never happen. No error, no memo, no user info. How?'); + throw 'Something went wrong.'; + } + } else if (response.statusCode == 500) { var string = await response.stream.bytesToString(); - var tokenResponse = VideoUploadLoginResponse.fromJsonString(string); - var cookie = response.headers['set-cookie']; - if (tokenResponse.error != null && tokenResponse.error!.isNotEmpty) { - throw 'Error - ${tokenResponse.error}'; - } else if (tokenResponse.network == "hive" && - tokenResponse.banned != true && - tokenResponse.userId != null && - cookie != null && - cookie.isNotEmpty) { + var errorResponse = VideoUploadLoginResponse.fromJsonString(string); + if (errorResponse.error != null && + errorResponse.error!.isNotEmpty && + errorResponse.error == 'session expired') { const storage = FlutterSecureStorage(); - await storage.write(key: 'cookie', value: cookie); + await storage.delete(key: 'cookie'); String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; var newData = HiveUserData( username: user.username, postingKey: user.postingKey, - hasId: user.hasId, - hasExpiry: user.hasExpiry, - cookie: cookie, + keychainData: user.keychainData, + cookie: null, resolution: resolution, rpc: rpc, ); server.updateHiveUserData(newData); - return cookie; + return await getValidCookie(newData); } else { - log('This should never happen. No error, no user info. How?'); - throw 'Something went wrong.'; + throw 'Status code ${response.statusCode}'; } - } else if (loginResponse.network == "hive" && - loginResponse.banned != true && - loginResponse.userId != null && - user.cookie != null) { - return user.cookie!; - } else { - log('This should never happen. No error, no memo, no user info. How?'); - throw 'Something went wrong.'; - } - } else if (response.statusCode == 500) { - var string = await response.stream.bytesToString(); - var errorResponse = VideoUploadLoginResponse.fromJsonString(string); - if (errorResponse.error != null && - errorResponse.error!.isNotEmpty && - errorResponse.error == 'session expired') { - const storage = FlutterSecureStorage(); - await storage.delete(key: 'cookie'); - String resolution = await storage.read(key: 'resolution') ?? '480p'; - String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - var newData = HiveUserData( - username: user.username, - postingKey: user.postingKey, - hasId: user.hasId, - hasExpiry: user.hasExpiry, - cookie: null, - resolution: resolution, - rpc: rpc, - ); - server.updateHiveUserData(newData); - return await getValidCookie(newData); } else { throw 'Status code ${response.statusCode}'; } - } else { - throw 'Status code ${response.statusCode}'; + } catch (e){ + throw e; } } From d8c11a2bff83144f5a22c66ae248eebdaa65741b Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sun, 22 Jan 2023 21:09:39 +0530 Subject: [PATCH 153/466] Publishing video. --- .flutter-plugins-dependencies | 2 +- ios/Runner/public/index.html | 22 ++++++++++++++++--- .../update_video/video_details_info.dart | 14 ++++++++++-- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 069c4e1d..005bb5da 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-22 18:36:21.554037","version":"3.7.0-1.4.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-22 21:03:12.133917","version":"3.7.0-1.4.pre"} \ No newline at end of file diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index 842b17cc..ee043453 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -226,7 +226,7 @@ community, ipfsHash, hasKey, - hasAuthKey, + hasAuthKey ) { let description = atob(dDescription); description = decodeURIComponent(escape(description)); @@ -298,6 +298,13 @@ const value = parseInt(beneWeights.split(",")[index]); newBen.push({ account: string, weight: value }); }); + newBen.sort((a, b) => { + let fa = a.account.toLowerCase(), + fb = b.account.toLowerCase(); + if (fa < fb) return -1; + if (fa > fb) return 1; + return 0; + }); let benefactor_global = [[0, { beneficiaries: newBen }]]; let comment_options = [ "comment_options", @@ -340,7 +347,12 @@ operations.push(comment_options); operations.push(customJson); console.log(`operations are ${JSON.stringify(operations)}`); - if (hasKey !== null && hasToken !== null && hasKey.length > 0 && hasToken.length > 0) { + if ( + hasKey !== null && + hasAuthKey !== null && + hasKey.length > 0 && + hasAuthKey.length > 0 + ) { const sign_data = { key_type: "posting", ops: operations, @@ -459,13 +471,17 @@ console.error("decryption failed", e.message); click_logout(); } - break; case "auth_nack": click_logout(); break; case "sign_wait": alert(`transaction ${message.uuid} is waiting for approval`); + replyToNative({ + type: "postVideo", + valid: true, + error: `Transaction ${message.uuid} is waiting for approval. Open HiveKeychain app, approve, come back here & hit Save button again.`, + }); break; case "sign_ack": console.log(`transaction ${message.uuid} approved`); diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index 48084df4..b5e11185 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -45,6 +45,7 @@ class _VideoDetailsInfoState extends State { final ImagePicker _picker = ImagePicker(); var selectedCommunity = 'hive-181335'; var selectedCommunityVisibleName = 'Threespeak'; + String? hiveKeychainTransactionId; void showError(String string) { var snackBar = SnackBar(content: Text('Error: $string')); @@ -103,9 +104,11 @@ class _VideoDetailsInfoState extends State { processText = 'Updating video info'; }); try { + // we wait for 15 seconds to wait for RPC node to have latest blocks + // if video is already published, we want to avoid. + await Future.delayed(const Duration(seconds: 15), () {}); var doesPostNotExist = await Communicator() .doesPostNotExist(widget.item.owner, widget.item.permlink, user.rpc); - await Future.delayed(const Duration(seconds: 1), () {}); if (doesPostNotExist != true) { await Communicator().updatePublishState(user, widget.item.id); setState(() { @@ -158,7 +161,7 @@ class _VideoDetailsInfoState extends State { log('Response from platform $response'); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); if (bridgeResponse.error == "success") { - await Future.delayed(const Duration(seconds: 5), () {}); + await Future.delayed(const Duration(seconds: 15), () {}); await Communicator().updatePublishState(user, v.id); setState(() { isCompleting = false; @@ -166,6 +169,13 @@ class _VideoDetailsInfoState extends State { showMessage('Congratulations. Your video is published.'); showMyDialog(); }); + } else if (bridgeResponse.error.startsWith("Transaction ")) { + setState(() { + isCompleting = false; + processText = ''; + hiveKeychainTransactionId = bridgeResponse.error.split(" ")[1]; + }); + showMessage(bridgeResponse.error); } else { throw bridgeResponse.error; } From 9ccae9ebf57cb2469b4d22e3c0d43d485c774234 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 26 Jan 2023 17:38:45 +0530 Subject: [PATCH 154/466] commit --- .flutter-plugins-dependencies | 2 +- lib/src/utils/communicator.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 005bb5da..8b1424e1 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-22 21:03:12.133917","version":"3.7.0-1.4.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-23 20:07:24.186728","version":"3.7.0-1.4.pre"} \ No newline at end of file diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index a626d0ad..dce0a793 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -33,7 +33,7 @@ class Communicator { // static const tsServer = "http://localhost:13050"; // static const fsServer = "http://localhost:1080/files"; - // iOS Device + // iOS Devices - Local Server Testing static const tsServer = "http://192.168.29.239:13050"; static const fsServer = "http://192.168.29.239:1080/files"; From d5ec276c362bfdcb869bd42914cb10ca3e91823d Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 26 Jan 2023 20:40:16 +0530 Subject: [PATCH 155/466] socket connection on dart --- .flutter-plugins | 35 ++- .flutter-plugins-dependencies | 2 +- .idea/libraries/Flutter_Plugins.xml | 35 ++- assets/hiveauth_icon.png | Bin 0 -> 8177 bytes flutter_01.log | 118 +++++++++++ ios/Podfile.lock | 15 +- lib/main.dart | 63 +----- .../models/user_stream/hive_user_stream.dart | 4 + lib/src/screens/login/ha_login_screen.dart | 147 +++++++++++++ lib/src/screens/login/login_screen.dart | 70 +----- .../account_settings_screen.dart | 7 +- .../screens/my_account/my_account_screen.dart | 24 --- lib/src/screens/settings/settings_screen.dart | 15 +- lib/src/utils/communicator.dart | 3 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 +- pubspec.lock | 200 ++++++++++-------- pubspec.yaml | 5 + 17 files changed, 472 insertions(+), 273 deletions(-) create mode 100644 assets/hiveauth_icon.png create mode 100644 flutter_01.log create mode 100644 lib/src/screens/login/ha_login_screen.dart diff --git a/.flutter-plugins b/.flutter-plugins index 60c9dd4b..a2e3eadf 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -6,23 +6,22 @@ device_info_plus_macos=/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_m device_info_plus_web=/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/ device_info_plus_windows=/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/ ffmpeg_kit_flutter=/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/ -file_picker=/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/ +file_picker=/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/ flutter_plugin_android_lifecycle=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/ flutter_secure_storage=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/ flutter_secure_storage_linux=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/ flutter_secure_storage_macos=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/ flutter_secure_storage_web=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/ flutter_secure_storage_windows=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/ -image_picker=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker-0.8.6/ -image_picker_android=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/ +image_picker=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker-0.8.6+1/ +image_picker_android=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/ image_picker_for_web=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/ -image_picker_ios=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/ +image_picker_ios=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/ images_picker=/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/ -path_provider=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider-2.0.11/ +path_provider=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider-2.0.12/ path_provider_android=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/ -path_provider_ios=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/ +path_provider_foundation=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/ path_provider_linux=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/ -path_provider_macos=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/ path_provider_windows=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/ permission_handler=/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler-10.2.0/ permission_handler_android=/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/ @@ -33,18 +32,18 @@ share_plus_linux=/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/ share_plus_macos=/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/ share_plus_web=/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/ share_plus_windows=/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/ -url_launcher=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher-6.1.7/ -url_launcher_android=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/ -url_launcher_ios=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/ -url_launcher_linux=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/ -url_launcher_macos=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/ -url_launcher_web=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/ -url_launcher_windows=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/ +url_launcher=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher-6.1.8/ +url_launcher_android=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/ +url_launcher_ios=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/ +url_launcher_linux=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/ +url_launcher_macos=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/ +url_launcher_web=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/ +url_launcher_windows=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/ video_compress=/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/ -video_player=/Users/sagar/.pub-cache/hosted/pub.dev/video_player-2.4.8/ -video_player_android=/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/ -video_player_avfoundation=/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/ -video_player_web=/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/ +video_player=/Users/sagar/.pub-cache/hosted/pub.dev/video_player-2.5.1/ +video_player_android=/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/ +video_player_avfoundation=/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/ +video_player_web=/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/ video_player_web_hls=/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/ video_thumbnail=/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/ wakelock=/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 8b1424e1..f4e1a095 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+1/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.17/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.7/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.22/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.9/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.1/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.3/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.13/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.12/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-23 20:07:24.186728","version":"3.7.0-1.4.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-26 20:39:35.510974","version":"3.7.0-1.5.pre"} \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 88fdd3a1..770ef48d 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -4,50 +4,49 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/assets/hiveauth_icon.png b/assets/hiveauth_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..54e9bb9eca37fe7c75a8a62ae9d407df1c0f372e GIT binary patch literal 8177 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%0Af7}&@5PmQidTqk49I}%db?^}I9f5Mzd z(*YNXad_4=DgmEhGBxb>r;R}9_kd57jiE#rb|nm6(&q5!hY7dC8je@3Sw z5P9$`G$L~ke2{F>+;#bFOkv^!Vd0r0N=hU>^&0ORk%f)us=Vx+onTw4ho$BVa+PGz^SaMM>mH*%I4zsCMO#T9h_7*dB#KeRp0>D$ zm#;qg*}gc5(0>SZ7RHP@;9| zA78CR2ejO`q)lzUI_w4A3_Batk+~&&RFApQoY;}sKJROLg*Oh3HLPlvo<5)TSl~X< zY66edl{pBTfj&e`%~S3luvJV-?s7cJ@B9J!$=&Jh6{SfMO*V3#&Ne+j{~eq3tQpm} zroRHrQH`Mq63mh9g6HfkHWbskFI!u6(=f~BHx#oKc8v{b4mLY}#Wh0a(>*b);(y9l zuUw4`k6WL_o7uWjSK4SFymfo4Li5GpER1~9 z+o?8yZmmp(I?8MB#iw_Dthr)x0>ZeSPdqUXq(5JQE2M$hx69FezA%wNV|!eU=XQ$M z+T&Ms4I@&dU~B1DpCY;s8}?X!5I&VjQYx0uiwzls#6t6lS*GpPWaf8pjiuBQzR_=q zpvI$kpAqja8XqN+coKx1J|{Gp6pQm2lernTaZ!_I%`M6`U*9u8*(Xr8xrNV~qFTXx?d@&^{LkH0I;ZMr@yfjjAj+ePxj z$5k9k=tW>|+06C)PiijCS1Uea;O+_?V49;-*9S!$vtG5#@`{n!L4!Fpd}xEmkGv;6 zGwG$q&VKPJ&4Avg?x~9soSrt(28~Eitk(ZpnR)@LZTw|vqZ*yCsF+;LEtYN>X)5yg z(B~QuCwA)sSxa1nZ)dZLtVy=AT;xR!3QyI!vmz0D@2e0vcl?D`kESl!(BYJgW)csUC=lZhM+v@?bN@uLXRM=Gv`O>Aw0u-KBPGRP zKnO@7Uz{SvxYnbq@`9+kx5@jazWhiEt<%e#rl+Y=YCDf6*~jz%Q>=qP^fH>JzCUEe zTTRTx3h|BLk-)hQQN|g_-LjNCD@g&Uv literal 0 HcmV?d00001 diff --git a/flutter_01.log b/flutter_01.log new file mode 100644 index 00000000..4ae32a64 --- /dev/null +++ b/flutter_01.log @@ -0,0 +1,118 @@ +Flutter crash report. +Please report a bug at https://github.com/flutter/flutter/issues. + +## command + +flutter pub get + +## exception + +PathNotFoundException: PathNotFoundException: Cannot open file, path = '/Applications/flutter/flutter/version' (OS Error: No such file or directory, errno = 2) + +``` +#0 _File.throwIfError (dart:io/file_impl.dart:629:7) +#1 _File.openSync (dart:io/file_impl.dart:473:5) +#2 _File.readAsBytesSync (dart:io/file_impl.dart:533:18) +#3 _File.readAsStringSync (dart:io/file_impl.dart:578:18) +#4 ForwardingFile.readAsStringSync (package:file/src/forwarding/forwarding_file.dart:99:16) +#5 ErrorHandlingFile.readAsStringSync. (package:flutter_tools/src/base/error_handling_io.dart:222:22) +#6 _runSync (package:flutter_tools/src/base/error_handling_io.dart:600:14) +#7 ErrorHandlingFile.readAsStringSync (package:flutter_tools/src/base/error_handling_io.dart:221:12) +#8 _DefaultPub.get (package:flutter_tools/src/dart/pub.dart:360:50) + +#9 PackagesGetCommand._runPubGet (package:flutter_tools/src/commands/packages.dart:140:7) + +#10 PackagesGetCommand.runCommand (package:flutter_tools/src/commands/packages.dart:175:5) + +#11 FlutterCommand.run. (package:flutter_tools/src/runner/flutter_command.dart:1257:27) + +#12 AppContext.run. (package:flutter_tools/src/base/context.dart:150:19) + +#13 CommandRunner.runCommand (package:args/command_runner.dart:209:13) + +#14 FlutterCommandRunner.runCommand. (package:flutter_tools/src/runner/flutter_command_runner.dart:283:9) + +#15 AppContext.run. (package:flutter_tools/src/base/context.dart:150:19) + +#16 FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:229:5) + +#17 run.. (package:flutter_tools/runner.dart:64:9) + +#18 AppContext.run. (package:flutter_tools/src/base/context.dart:150:19) + +#19 main (package:flutter_tools/executable.dart:91:3) + +``` + +## flutter doctor + +``` +[☠] Flutter (the doctor check crashed) + ✗ Due to an error, the doctor check did not complete. If the error message below is not helpful, please let us know about this issue at https://github.com/flutter/flutter/issues. + ✗ Exception: Could not find directory at /Applications/flutter/flutter/bin/cache/dart-sdk/bin/resources/devtools + • #0 Cache.devToolsVersion (package:flutter_tools/src/cache.dart:384:9) + #1 _DefaultDoctorValidatorsProvider.validators. (package:flutter_tools/src/doctor.dart:126:46) + #2 FlutterValidator.validate (package:flutter_tools/src/doctor.dart:530:84) + #3 Doctor.startValidatorTasks. (package:flutter_tools/src/doctor.dart:250:72) + #4 asyncGuard. (package:flutter_tools/src/base/async_guard.dart:111:32) + #5 _rootRun (dart:async/zone.dart:1398:13) + #6 _CustomZone.run (dart:async/zone.dart:1300:19) + #7 _runZoned (dart:async/zone.dart:1803:10) + #8 runZonedGuarded (dart:async/zone.dart:1791:12) + #9 runZoned (dart:async/zone.dart:1743:12) + #10 asyncGuard (package:flutter_tools/src/base/async_guard.dart:109:3) + #11 Doctor.startValidatorTasks (package:flutter_tools/src/doctor.dart:242:9) + #12 DoctorText._validatorTasks (package:flutter_tools/src/doctor.dart:739:60) + #13 DoctorText._validatorTasks (package:flutter_tools/src/doctor.dart) + #14 DoctorText._runDiagnosis (package:flutter_tools/src/doctor.dart:743:53) + #15 DoctorText.text (package:flutter_tools/src/doctor.dart:735:36) + #16 DoctorText.text (package:flutter_tools/src/doctor.dart) + #17 _createLocalCrashReport (package:flutter_tools/runner.dart:206:51) + #18 _handleToolError (package:flutter_tools/runner.dart:168:31) + + #19 AppContext.run. (package:flutter_tools/src/base/context.dart:150:19) + + #20 main (package:flutter_tools/executable.dart:91:3) + + + +[!] Android toolchain - develop for Android devices (Android SDK version 33.0.0) + • Android SDK at /Users/sagar/Library/Android/sdk + • Platform android-33, build-tools 33.0.0 + • Java binary at: /Library/Java/JavaVirtualMachines/temurin-8.jdk/Contents/Home/bin/java + • Java version OpenJDK Runtime Environment (Temurin)(build 1.8.0_322-b06) + ✗ Android license status unknown. + Run `flutter doctor --android-licenses` to accept the SDK licenses. + See https://flutter.dev/docs/get-started/install/macos#android-setup for more details. + +[✓] Xcode - develop for iOS and macOS (Xcode 14.2) + • Xcode at /Applications/Xcode.app/Contents/Developer + • Build 14C18 + • CocoaPods version 1.11.3 + +[✓] Chrome - develop for the web + • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome + +[!] Android Studio (version 2022.1) + • Android Studio at /Applications/Android Studio.app/Contents + • Flutter plugin can be installed from: + 🔨 https://plugins.jetbrains.com/plugin/9212-flutter + • Dart plugin can be installed from: + 🔨 https://plugins.jetbrains.com/plugin/6351-dart + ✗ Unable to find bundled Java version. + • Try updating or re-installing Android Studio. + +[✓] VS Code (version 1.74.3) + • VS Code at /Applications/Visual Studio Code.app/Contents + • Flutter extension version 3.58.0 + +[✓] Connected device (3 available) + • iPhone 14 Pro (mobile) • 01D7AC4F-11B8-456A-8FD4-8275C0814F45 • ios • com.apple.CoreSimulator.SimRuntime.iOS-16-2 (simulator) + • macOS (desktop) • macos • darwin-arm64 • macOS 13.1 22C65 darwin-arm64 + • Chrome (web) • chrome • web-javascript • Google Chrome 109.0.5414.119 + +[✓] HTTP Host Availability + • All required HTTP hosts are available + +! Doctor found issues in 3 categories. +``` diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 7340dfb8..380851da 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -73,8 +73,9 @@ PODS: - libwebp/mux (1.2.3): - libwebp/demux - libwebp/webp (1.2.3) - - path_provider_ios (0.0.1): + - path_provider_foundation (0.0.1): - Flutter + - FlutterMacOS - permission_handler_apple (9.0.4): - Flutter - PINCache (3.0.3): @@ -118,7 +119,7 @@ DEPENDENCIES: - FYVideoCompressor - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - images_picker (from `.symlinks/plugins/images_picker/ios`) - - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) @@ -161,8 +162,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/image_picker_ios/ios" images_picker: :path: ".symlinks/plugins/images_picker/ios" - path_provider_ios: - :path: ".symlinks/plugins/path_provider_ios/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/ios" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" share_plus: @@ -188,7 +189,7 @@ SPEC CHECKSUMS: DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 ffmpeg-kit-ios-https: cec24d405b511e4f274980d8a9c751d384f89558 ffmpeg_kit_flutter: e2f0bd6b75e361faeee3b34c70650d3ec6ec35d0 - file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95 + file_picker: ce3938a0df3cc1ef404671531facef740d03f920 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be FYVideoCompressor: 70440458b5fe699f05e4a8a9011f1e4080056330 @@ -197,14 +198,14 @@ SPEC CHECKSUMS: image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb images_picker: fa9364e3a7d3083c49f865fcfb2b9e7cdc574d3a libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c - path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 + path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20 SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 - url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de + url_launcher_ios: ae1517e5e344f5544fb090b079e11f399dfbe4d2 video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1 diff --git a/lib/main.dart b/lib/main.dart index a216929d..5e6a5d9e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,9 @@ +import 'dart:io'; + import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; +import 'package:acela/src/utils/communicator.dart'; // import 'package:firebase_core/firebase_core.dart'; // import 'package:firebase_messaging/firebase_messaging.dart'; @@ -9,16 +12,7 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:overlay_support/overlay_support.dart'; import 'package:provider/provider.dart'; - -class PushNotification { - PushNotification({ - this.title, - this.body, - }); - - String? title; - String? body; -} +import 'package:web_socket_channel/web_socket_channel.dart'; Future main() async { await dotenv.load(fileName: ".env"); @@ -35,6 +29,9 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { late final Future _futureToLoadData; + WebSocketChannel socket = WebSocketChannel.connect( + Uri.parse(Communicator.hiveAuthServer), + ); // late final FirebaseMessaging _messaging; // Create storage @@ -76,6 +73,7 @@ class _MyAppState extends State { postingKey: null, username: null, rpc: 'api.hive.blog', + socket: socket, ), child: StreamProvider.value( value: server.theme, @@ -93,51 +91,7 @@ class _MyAppState extends State { _futureToLoadData = loadData(); } - // Future handlingNotification() async { - // try { - // // 3. On iOS, this helps to take the user permissions - // NotificationSettings settings = await _messaging.requestPermission( - // alert: true, - // badge: false, - // provisional: false, - // sound: true, - // ); - // if (settings.authorizationStatus == AuthorizationStatus.authorized) { - // print('User granted permission'); - // FirebaseMessaging.onMessage.listen((RemoteMessage message) { - // // Parse the message received - // PushNotification notification = PushNotification( - // title: message.notification?.title, - // body: message.notification?.body, - // ); - // - // setState(() { - // showSimpleNotification( - // Text(notification.title ?? "No title for notification"), - // // leading: NotificationBadge(totalNotifications: _totalNotifications), - // subtitle: Text(notification.body ?? - // "No text provided for info of notification"), - // background: Colors.cyan.shade700, - // duration: Duration(seconds: 2), - // ); - // }); - // }); - // } else { - // print('User declined or has not accepted permission'); - // } - // } catch (e) { - // print("Something went wrong in setting up fcm ${e.toString()}"); - // } - // } - Future loadData() async { - // setup firebase - // await Firebase.initializeApp( - // options: DefaultFirebaseOptions.currentPlatform); - // _messaging = FirebaseMessaging.instance; - // handle notifications - // await handlingNotification(); - // load storage const storage = FlutterSecureStorage(); String? username = await storage.read(key: 'username'); String? postingKey = await storage.read(key: 'postingKey'); @@ -166,6 +120,7 @@ class _MyAppState extends State { cookie: cookie, resolution: resolution, rpc: rpc, + socket: socket, ), ); } diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index cefdec8c..f1945dc5 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -1,3 +1,5 @@ +import 'package:web_socket_channel/web_socket_channel.dart'; + class HiveKeychainData { String hasId; String hasExpiry; @@ -15,6 +17,7 @@ class HiveUserData { HiveKeychainData? keychainData; String resolution; String rpc; + WebSocketChannel? socket; HiveUserData({ required this.username, @@ -23,5 +26,6 @@ class HiveUserData { required this.cookie, required this.resolution, required this.rpc, + required this.socket, }); } diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart new file mode 100644 index 00000000..e7c12056 --- /dev/null +++ b/lib/src/screens/login/ha_login_screen.dart @@ -0,0 +1,147 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/utils/safe_convert.dart'; +import 'package:encryptor/encryptor.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; +import 'package:qr_flutter/qr_flutter.dart'; +import 'package:uuid/uuid.dart'; + +class HiveAuthLoginScreen extends StatefulWidget { + const HiveAuthLoginScreen({Key? key}) : super(key: key); + + @override + State createState() => _HiveAuthLoginScreenState(); +} + +class _HiveAuthLoginScreenState extends State { + var isLoading = false; + var username = ''; + var appData = { + "name": "3Speak Mobile iOS App", + "description": "3Speak Mobile iOS App with HAS Integration", + }; + var appKey = Uuid().v4(); + String? authUuid; + String? authKey; + String? token; + String? expire; + static const platform = MethodChannel('com.example.acela/auth'); + String? qrString; + + @override + void initState() { + super.initState(); + } + + void showError(String string) { + var snackBar = SnackBar(content: Text('Error: $string')); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + Widget _hiveUserName() { + return TextField( + decoration: InputDecoration( + icon: const Icon(Icons.person), + label: const Text('Hive Username'), + hintText: 'Enter Hive username here', + ), + autocorrect: false, + onChanged: (value) { + setState(() { + username = value; + }); + }, + enabled: isLoading ? false : true, + ); + } + + Widget _hasButton(HiveUserData data) { + return ElevatedButton( + onPressed: () async { + if (username.isEmpty) return; + setState(() { + isLoading = true; + authKey = Uuid().v4(); + if (authKey == null) return; + var authData = { + "app": appData, + // "token": token, + // "challenge": null, + }; + var jsonString = json.encode(authData); + var encrypted = Encryptor.encrypt(authKey!, jsonString); + var payload = { + "cmd": "auth_req", + "account": username, + "data": encrypted, + }; + var payloadJsonString = json.encode(payload); + data.socket?.sink.add(payloadJsonString); + }); + }, + child: const Text('Log in with Hive Auth'), + ); + } + + Widget _loginForm(HiveUserData appData) { + return Container( + margin: EdgeInsets.all(10), + child: Column( + children: [ + _hiveUserName(), + SizedBox(height: 20), + isLoading ? CircularProgressIndicator() : qrString == null ? _hasButton(appData) : QrImage( + data: qrString!, + version: QrVersions.auto, + size: 200.0, + ), + StreamBuilder( + stream: appData.socket?.stream, + builder: (context, snapshot) { + var data = snapshot.data as String?; + if (snapshot.hasData && data != null && data.isNotEmpty == true) { + var map = json.decode(data) as Map; + var cmd = asString(map, 'cmd'); + if (cmd.isNotEmpty) { + switch (cmd) { + case "auth_wait": + var uuid = asString(map, 'uuid'); + var qr = json.encode({ + "account": username, + "uuid": uuid, + "key": authKey, + "host": Communicator.hiveAuthServer + }); + setState(() { + this.qrString = qr; + }); + break; + default: + log('Default case here'); + } + } + } + return Container(); + }, + ) + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + var data = Provider.of(context); + return Scaffold( + appBar: AppBar( + title: const Text('Login with Hive Auth'), + ), + body: _loginForm(data), + ); + } +} diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index b62f5623..0632541c 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/login/ha_login_screen.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/crypto_manager.dart'; import 'package:flutter/material.dart'; @@ -53,6 +54,7 @@ class _LoginScreenState extends State { cookie: null, resolution: resolution, rpc: rpc, + socket: appData.socket, ), ); Navigator.of(context).pop(); @@ -113,63 +115,6 @@ class _LoginScreenState extends State { ); } - Widget _hasButton() { - return ElevatedButton( - onPressed: () async { - if (username.isNotEmpty) { - var platform = const MethodChannel('blog.hive.auth/bridge'); - var values = await platform.invokeMethod('getUserInfo'); - var valuesResponse = LoginBridgeResponse.fromJsonString(values); - if (valuesResponse.data?.startsWith("undefined,undefined") == true) { - final String authStr = - await platform.invokeMethod('getRedirectUri', { - 'username': username, - }); - log('Hive auth string is $authStr'); - var bridgeResponse = LoginBridgeResponse.fromJsonString(authStr); - if (bridgeResponse.data != null) { - var url = Uri.parse(bridgeResponse.data!); - launchUrl(url); - } - } else { - debugPrint("Successful login"); - String resolution = await storage.read(key: 'resolution') ?? '480p'; - String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - var hasId = valuesResponse.data!.split(",")[0]; - var hasExpiry = valuesResponse.data!.split(",")[1]; - var hasAuthKey = valuesResponse.data!.split(",")[2]; - await storage.write(key: 'username', value: username); - await storage.write(key: 'hasId', value: hasId); - await storage.write(key: 'hasExpiry', value: hasExpiry); - await storage.write(key: 'hasAuthKey', value: hasAuthKey); - await storage.delete(key: 'cookie'); - server.updateHiveUserData( - HiveUserData( - username: username, - postingKey: null, - keychainData: HiveKeychainData( - hasId: hasId, - hasExpiry: hasExpiry, - hasAuthKey: hasAuthKey, - ), - cookie: null, - resolution: resolution, - rpc: rpc, - ), - ); - Navigator.of(context).pop(); - setState(() { - isLoading = false; - }); - } - } else { - showError('Please enter hive username'); - } - }, - child: Image.asset('assets/hive-keychain-image.png'), - ); - } - Widget _loginForm(HiveUserData appData) { return Container( margin: EdgeInsets.all(10), @@ -177,9 +122,6 @@ class _LoginScreenState extends State { children: [ _hiveUserName(), SizedBox(height: 20), - _hasButton(), - SizedBox(height: 50), - const Text('- OR -'), _hivePostingKey(), SizedBox(height: 20), isLoading @@ -213,6 +155,14 @@ class _LoginScreenState extends State { 'Concerned about security? Rest assured.\nYour posting key never leaves this app.\nIt is securely stored on your device ONLY.\nNo one, including us, will have it.'); }, icon: Icon(Icons.help), + ), + IconButton( + onPressed: () { + const screen = HiveAuthLoginScreen(); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + icon: Image.asset('assets/hiveauth_icon.png'), ) ], ), diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index 2eeb9fa9..d996160e 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -2,6 +2,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:provider/provider.dart'; class AccountSettingsScreen extends StatefulWidget { const AccountSettingsScreen({Key? key}) : super(key: key); @@ -11,7 +12,7 @@ class AccountSettingsScreen extends StatefulWidget { } class _AccountSettingsScreenState extends State { - void logout() async { + void logout(HiveUserData data) async { // Create storage const storage = FlutterSecureStorage(); await storage.delete(key: 'username'); @@ -30,6 +31,7 @@ class _AccountSettingsScreenState extends State { cookie: null, resolution: resolution, rpc: rpc, + socket: data.socket, ), ); Navigator.of(context).pop(); @@ -38,6 +40,7 @@ class _AccountSettingsScreenState extends State { @override Widget build(BuildContext context) { + var data = Provider.of(context); return Scaffold( appBar: AppBar( title: const Text('Settings'), @@ -49,7 +52,7 @@ class _AccountSettingsScreenState extends State { leading: const Icon(Icons.logout), title: const Text('Log Out'), onTap: () { - logout(); + logout(data); }, ), ], diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 01df8c39..0b8b3923 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -22,30 +22,6 @@ class MyAccountScreen extends StatefulWidget { class _MyAccountScreenState extends State { Future>? loadVideos; - void logout() async { - // Create storage - const storage = FlutterSecureStorage(); - await storage.delete(key: 'username'); - await storage.delete(key: 'postingKey'); - await storage.delete(key: 'cookie'); - await storage.delete(key: 'hasId'); - await storage.delete(key: 'hasExpiry'); - await storage.delete(key: 'hasAuthKey'); - String resolution = await storage.read(key: 'resolution') ?? '480p'; - String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - server.updateHiveUserData( - HiveUserData( - username: null, - postingKey: null, - keychainData: null, - cookie: null, - resolution: resolution, - rpc: rpc, - ), - ); - Navigator.of(context).pop(); - } - void showError(String string) { var snackBar = SnackBar(content: Text('Error: $string')); ScaffoldMessenger.of(context).showSnackBar(snackBar); diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index cd83f2c9..a670b151 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -36,7 +36,7 @@ class _SettingsScreenState extends State { ); } - BottomSheetAction getAction(String optionName) { + BottomSheetAction getAction(String optionName, HiveUserData appData) { return BottomSheetAction( title: Text(optionName), onPressed: (context) async { @@ -69,6 +69,7 @@ class _SettingsScreenState extends State { hasId: hasId, ) : null, + socket: appData.socket, ), ); loadRes(); @@ -76,12 +77,16 @@ class _SettingsScreenState extends State { ); } - void tappedVideoRes() { + void tappedVideoRes(HiveUserData appData) { showAdaptiveActionSheet( context: context, title: const Text('Set Default video resolution to'), androidBorderRadius: 30, - actions: [getAction('480p'), getAction('720p'), getAction('1080p')], + actions: [ + getAction('480p', appData), + getAction('720p', appData), + getAction('1080p', appData), + ], cancelAction: CancelAction(title: const Text('Cancel')), ); } @@ -100,13 +105,14 @@ class _SettingsScreenState extends State { } Widget _video(BuildContext context) { + var data = Provider.of(context); return ListTile( leading: const Icon(Icons.video_collection), title: const Text("Video Resolution"), subtitle: const Text("Change Default resolution"), trailing: Text(res), onTap: () async { - tappedVideoRes(); + tappedVideoRes(data); }, ); } @@ -126,6 +132,7 @@ class _SettingsScreenState extends State { cookie: user.cookie, resolution: user.resolution, rpc: serverUrl, + socket: user.socket, ), ); }, diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index dce0a793..6e54f24a 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -39,6 +39,7 @@ class Communicator { // static const hiveApiUrl = 'api.hive.blog'; static const threeSpeakCDN = 'https://ipfs-3speak.b-cdn.net'; + static const hiveAuthServer = 'wss://hive-auth.arcange.eu'; Future doesPostNotExist( String user, @@ -205,6 +206,7 @@ class Communicator { cookie: cookie, resolution: resolution, rpc: rpc, + socket: user.socket ); server.updateHiveUserData(newData); return cookie; @@ -238,6 +240,7 @@ class Communicator { cookie: null, resolution: resolution, rpc: rpc, + socket: user.socket, ); server.updateHiveUserData(newData); return await getValidCookie(newData); diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 0b6eafb4..7b364da5 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,7 +8,7 @@ import Foundation import device_info_plus_macos import ffmpeg_kit_flutter import flutter_secure_storage_macos -import path_provider_macos +import path_provider_foundation import share_plus_macos import url_launcher_macos import video_compress diff --git a/pubspec.lock b/pubspec.lock index 775f5d98..e303d2e7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "3444216bfd127af50bbe4862d8843ed44db946dd933554f0d7285e89f10e28ac" + sha256: "0c80aeab9bc807ab10022cd3b2f4cf2ecdf231949dc1ddd9442406a003f19201" url: "https://pub.dev" source: hosted - version: "50.0.0" + version: "52.0.0" adaptive_action_sheet: dependency: "direct main" description: @@ -21,18 +21,26 @@ packages: dependency: transitive description: name: analyzer - sha256: "68796c31f510c8455a06fed75fc97d8e5ad04d324a830322ab3efc9feb6201c1" + sha256: cd8ee83568a77f3ae6b913a36093a1c9b1264e7cb7f834d9ddd2311dade9c1f4 url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.4.0" args: dependency: transitive description: name: args - sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 + sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" + asn1lib: + dependency: transitive + description: + name: asn1lib + sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039 + url: "https://pub.dev" + source: hosted + version: "1.4.0" async: dependency: transitive description: @@ -86,10 +94,10 @@ packages: dependency: transitive description: name: buffer - sha256: "850b666e7d27c5cf42f39c43d3a9d37b7b35519b9715d9f85b418d76201518c6" + sha256: "8962c12174f53e2e848a6acd7ac7fd63d8a1a6a316c20c458a832d87eba5422a" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" build: dependency: transitive description: @@ -126,10 +134,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "6f48c61a9dcd2c3a9e62d3dcdab1ba382790e2f31026288cbabe55d6003c9c23" + sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.3" build_runner_core: dependency: transitive description: @@ -150,18 +158,18 @@ packages: dependency: transitive description: name: built_value - sha256: "59e08b0079bb75f7e27392498e26339387c1089c6bd58525a14eb8508637277b" + sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725" url: "https://pub.dev" source: hosted - version: "8.4.2" + version: "8.4.3" carousel_slider: dependency: "direct main" description: name: carousel_slider - sha256: "869a3f4f2ad0e8d029d9cefd20d2cafd0a50847b74e7aab3a8eec662b0c7d2ee" + sha256: "9c695cc963bf1d04a47bd6021f68befce8970bcd61d24938e1fb0918cf5d9c42" url: "https://pub.dev" source: hosted - version: "4.1.1" + version: "4.2.1" characters: dependency: transitive description: @@ -174,18 +182,18 @@ packages: dependency: transitive description: name: checked_yaml - sha256: dd007e4fb8270916820a0d66e24f619266b60773cddd082c6439341645af2659 + sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" chewie: dependency: "direct main" description: name: chewie - sha256: "7737b1b8b1f9df3b3751abfb0dea5efbebb7060c28eccdc3b0fa4a0d638eaf9f" + sha256: e9da4898ee4859825404f507969f57113c04ca0060e152b95c9afd73934126ad url: "https://pub.dev" source: hosted - version: "1.3.6" + version: "1.4.0" clock: dependency: transitive description: @@ -198,10 +206,10 @@ packages: dependency: transitive description: name: code_builder - sha256: "02ce3596b459c666530f045ad6f96209474e8fee6e4855940a3cee65fb872ec5" + sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe" url: "https://pub.dev" source: hosted - version: "4.3.0" + version: "4.4.0" collection: dependency: transitive description: @@ -314,6 +322,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.8" + encrypt: + dependency: transitive + description: + name: encrypt + sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb" + url: "https://pub.dev" + source: hosted + version: "5.0.1" + encryptor: + dependency: "direct main" + description: + name: encryptor + sha256: "865701525e720db64d1ce07c64446ecd02450772599fa9e2317dce62bb7761b6" + url: "https://pub.dev" + source: hosted + version: "0.0.1" fake_async: dependency: transitive description: @@ -358,10 +382,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "28f1c95692761e7b582d83d40da61295d489f4be0a368b2746ed2cdfe87e7fef" + sha256: d090ae03df98b0247b82e5928f44d1b959867049d18d73635e2e0bc3f49542b9 url: "https://pub.dev" source: hosted - version: "5.2.3" + version: "5.2.5" fixnum: dependency: transitive description: @@ -557,18 +581,18 @@ packages: dependency: "direct main" description: name: image_picker - sha256: a8f2f0aed50c03230ab37e93ca2905c50b6c4097245345956eb24a88f45328cd + sha256: f98d76672d309c8b7030c323b3394669e122d52b307d2bbd8d06bd70f5b2aabe url: "https://pub.dev" source: hosted - version: "0.8.6" + version: "0.8.6+1" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "822f71a53336bf1e638dbf955047080ca49ba0197f52c4fece9cf584c368648a" + sha256: b1cbfec0f5aef427a18eb573f5445af8c9c568626bf3388553e40c263d3f7368 url: "https://pub.dev" source: hosted - version: "0.8.5+3" + version: "0.8.5+5" image_picker_for_web: dependency: transitive description: @@ -581,10 +605,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: "1768087441bd69ca632249d212c26fa8d530552d37b4896a4dd8d6781435c147" + sha256: "39c013200046d14c58b71dc4fa3d00e425fc9c699d589136cd3ca018727c0493" url: "https://pub.dev" source: hosted - version: "0.8.6+1" + version: "0.8.6+6" image_picker_platform_interface: dependency: transitive description: @@ -613,10 +637,10 @@ packages: dependency: transitive description: name: io - sha256: "0d4c73c3653ab85bf696d51a9657604c900a370549196a91f33e4c39af760852" + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" js: dependency: transitive description: @@ -629,18 +653,18 @@ packages: dependency: "direct main" description: name: json_annotation - sha256: "3520fa844009431b5d4491a5a778603520cdc399ab3406332dcc50f93547258c" + sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "4.8.0" json_serializable: dependency: "direct dev" description: name: json_serializable - sha256: f3c2c18a7889580f71926f30c1937727c8c7d4f3a435f8f5e8b0ddd25253ef5d + sha256: "040088d9eb2337f3a51ddabe35261e2fea1c351e3dd29d755ed1290b6b700a75" url: "https://pub.dev" source: hosted - version: "6.5.4" + version: "6.6.0" lints: dependency: transitive description: @@ -701,10 +725,10 @@ packages: dependency: transitive description: name: mime - sha256: "52e38f7e1143ef39daf532117d6b8f8f617bf4bcd6044ed8c29040d20d269630" + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" nested: dependency: transitive description: @@ -741,10 +765,10 @@ packages: dependency: "direct main" description: name: path_provider - sha256: "050e8e85e4b7fecdf2bb3682c1c64c4887a183720c802d323de8a5fd76d372dd" + sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95 url: "https://pub.dev" source: hosted - version: "2.0.11" + version: "2.0.12" path_provider_android: dependency: transitive description: @@ -753,14 +777,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.22" - path_provider_ios: + path_provider_foundation: dependency: transitive description: - name: path_provider_ios - sha256: "03d639406f5343478352433f00d3c4394d52dac8df3d847869c5e2333e0bbce8" + name: path_provider_foundation + sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74" url: "https://pub.dev" source: hosted - version: "2.0.11" + version: "2.1.1" path_provider_linux: dependency: transitive description: @@ -769,14 +793,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.7" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - sha256: "2a97e7fbb7ae9dcd0dfc1220a78e9ec3e71da691912e617e8715ff2a13086ae8" - url: "https://pub.dev" - source: hosted - version: "2.0.6" path_provider_platform_interface: dependency: transitive description: @@ -885,10 +901,10 @@ packages: dependency: "direct main" description: name: provider - sha256: e1e7413d70444ea3096815a60fe5da1b11bda8a9dc4769252cc82c53536f8bcc + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f url: "https://pub.dev" source: hosted - version: "6.0.4" + version: "6.0.5" pub_semver: dependency: transitive description: @@ -905,6 +921,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" + qr: + dependency: transitive + description: + name: qr + sha256: "5c4208b4dc0d55c3184d10d83ee0ded6212dc2b5e2ba17c5a0c0aab279128d21" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + qr_flutter: + dependency: "direct main" + description: + name: qr_flutter + sha256: c5c121c54cb6dd837b9b9d57eb7bc7ec6df4aee741032060c8833a678c80b87e + url: "https://pub.dev" + source: hosted + version: "4.0.0" share_plus: dependency: "direct main" description: @@ -1067,10 +1099,10 @@ packages: dependency: transitive description: name: timing - sha256: c386d07d7f5efc613479a7c4d9d64b03710b03cfaa7e8ad5f2bfb295a1f0dfad + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" tus_client: dependency: "direct main" description: @@ -1099,42 +1131,42 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "3c92b0efb5e9dcb8f846aefabf9f0f739f91682ed486b991ceda51c288e60896" + sha256: "698fa0b4392effdc73e9e184403b627362eb5fbf904483ac9defbb1c2191d809" url: "https://pub.dev" source: hosted - version: "6.1.7" + version: "6.1.8" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "6f91d30ce9060c204b2dbe728adb300750fa4b228e8f7ed1b961aa1ceb728799" + sha256: "3e2f6dfd2c7d9cd123296cab8ef66cfc2c1a13f5845f42c7a0f365690a8a7dd1" url: "https://pub.dev" source: hosted - version: "6.0.22" + version: "6.0.23" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "6ba7dddee26c9fae27c9203c424631109d73c8fa26cfa7bc3e35e751cb87f62e" + sha256: bb328b24d3bccc20bdf1024a0990ac4f869d57663660de9c936fb8c043edefe3 url: "https://pub.dev" source: hosted - version: "6.0.17" + version: "6.0.18" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "360fa359ab06bcb4f7c5cd3123a2a9a4d3364d4575d27c4b33468bd4497dd094" + sha256: "318c42cba924e18180c029be69caf0a1a710191b9ec49bb42b5998fdcccee3cc" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: a9b3ea9043eabfaadfa3fb89de67a11210d85569086d22b3854484beab8b3978 + sha256: "41988b55570df53b3dd2a7fc90c76756a963de6a8c5f8e113330cb35992e2094" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" url_launcher_platform_interface: dependency: transitive description: @@ -1147,20 +1179,20 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "5669882643b96bb6d5786637cac727c6e918a790053b09245fd4513b8a07df2a" + sha256: "44d79408ce9f07052095ef1f9a693c258d6373dc3944249374e30eff7219ccb0" url: "https://pub.dev" source: hosted - version: "2.0.13" + version: "2.0.14" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: e3c3b16d3104260c10eea3b0e34272aaa57921f83148b0619f74c2eced9b7ef1 + sha256: b6217370f8eb1fd85c8890c539f5a639a01ab209a36db82c921ebeacefc7a615 url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.3" uuid: - dependency: transitive + dependency: "direct main" description: name: uuid sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" @@ -1187,26 +1219,26 @@ packages: dependency: "direct main" description: name: video_player - sha256: "7bfb0f889879beb2980550a4df07721e980b59a874fc2c1019a6f85eab44bb95" + sha256: "59f7f31c919c59cbedd37c617317045f5f650dc0eeb568b0b0de9a36472bdb28" url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.5.1" video_player_android: dependency: transitive description: name: video_player_android - sha256: d4d7313d1dc6f14d3414b98e2b268c3f34f4ac4ce4af51cf905e9a438edf0c77 + sha256: "984388511230bac63feb53b2911a70e829fe0976b6b2213f5c579c4e0a882db3" url: "https://pub.dev" source: hosted - version: "2.3.9" + version: "2.3.10" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: "3df559495634bba8feb24439ac0a28a380d4ff96be7990811dc4ec81299e8cfa" + sha256: d9f7a46d6a77680adb03ec05a381025d6e890ebe636637c6c3014cc3926b97e9 url: "https://pub.dev" source: hosted - version: "2.3.7" + version: "2.3.8" video_player_platform_interface: dependency: transitive description: @@ -1219,10 +1251,10 @@ packages: dependency: transitive description: name: video_player_web - sha256: ed949a3df5fe88533254bbdd242c3d8eea19ecbc4e7af90da84ef087533f584b + sha256: b649b07b8f8f553bee4a97a0a53d0fe78a70b115eafaf0105b612b32b05ddb99 url: "https://pub.dev" source: hosted - version: "2.0.12" + version: "2.0.13" video_player_web_hls: dependency: "direct main" description: @@ -1296,13 +1328,13 @@ packages: source: hosted version: "1.0.2" web_socket_channel: - dependency: transitive + dependency: "direct main" description: name: web_socket_channel - sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd" + sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" webview_flutter: dependency: "direct main" description: @@ -1339,18 +1371,18 @@ packages: dependency: transitive description: name: win32 - sha256: ca121dbbadb3e43b449053feab0cdf3f2bff93b107cacf0290e3d29f717374b6 + sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: "11541eedefbcaec9de35aa82650b695297ce668662bbd6e3911a7fabdbde589f" + sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 url: "https://pub.dev" source: hosted - version: "0.2.0+2" + version: "0.2.0+3" xml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9d77e39f..f3952161 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -70,6 +70,10 @@ dependencies: path_provider: ^2.0.11 images_picker: ^1.2.11 carousel_slider: ^4.1.1 + uuid: ^3.0.7 + web_socket_channel: ^2.3.0 + encryptor: ^0.0.1 + qr_flutter: ^4.0.0 dev_dependencies: flutter_test: @@ -102,6 +106,7 @@ flutter: - assets/branding/three_shorts_icon.png - assets/hive-keychain-image.png - assets/ipfs-logo.png + - assets/hiveauth_icon.png - .env # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg From 143b0749cf5c30b1297e1c8173d74c241ece465e Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 27 Jan 2023 00:48:11 +0530 Subject: [PATCH 156/466] socket work. --- .flutter-plugins-dependencies | 2 +- lib/main.dart | 2 + .../models/user_stream/hive_user_stream.dart | 2 + lib/src/screens/login/ha_login_screen.dart | 40 +++++++++++++------ lib/src/screens/login/login_screen.dart | 4 +- .../account_settings_screen.dart | 1 + lib/src/screens/settings/settings_screen.dart | 2 + lib/src/utils/communicator.dart | 4 +- pubspec.lock | 8 ++++ pubspec.yaml | 1 + 10 files changed, 49 insertions(+), 17 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index f4e1a095..aea09e6e 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-26 20:39:35.510974","version":"3.7.0-1.5.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-27 00:12:49.041375","version":"3.7.0-1.5.pre"} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 5e6a5d9e..cca6829a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -74,6 +74,7 @@ class _MyAppState extends State { username: null, rpc: 'api.hive.blog', socket: socket, + hiveAuthLoginQR: null, ), child: StreamProvider.value( value: server.theme, @@ -121,6 +122,7 @@ class _MyAppState extends State { resolution: resolution, rpc: rpc, socket: socket, + hiveAuthLoginQR: null, ), ); } diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index f1945dc5..2bcbb170 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -18,6 +18,7 @@ class HiveUserData { String resolution; String rpc; WebSocketChannel? socket; + String? hiveAuthLoginQR; HiveUserData({ required this.username, @@ -27,5 +28,6 @@ class HiveUserData { required this.resolution, required this.rpc, required this.socket, + required this.hiveAuthLoginQR, }); } diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index e7c12056..b47172bd 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -1,12 +1,14 @@ import 'dart:convert'; import 'dart:developer'; +import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/safe_convert.dart'; import 'package:encryptor/encryptor.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:pretty_qr_code/pretty_qr_code.dart'; import 'package:provider/provider.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:uuid/uuid.dart'; @@ -31,7 +33,6 @@ class _HiveAuthLoginScreenState extends State { String? token; String? expire; static const platform = MethodChannel('com.example.acela/auth'); - String? qrString; @override void initState() { @@ -65,7 +66,7 @@ class _HiveAuthLoginScreenState extends State { onPressed: () async { if (username.isEmpty) return; setState(() { - isLoading = true; + // isLoading = true; authKey = Uuid().v4(); if (authKey == null) return; var authData = { @@ -95,11 +96,16 @@ class _HiveAuthLoginScreenState extends State { children: [ _hiveUserName(), SizedBox(height: 20), - isLoading ? CircularProgressIndicator() : qrString == null ? _hasButton(appData) : QrImage( - data: qrString!, - version: QrVersions.auto, - size: 200.0, - ), + isLoading + ? CircularProgressIndicator() + : appData.hiveAuthLoginQR == null + ? _hasButton(appData) + : QrImage( + data: appData.hiveAuthLoginQR!, + // version: QrVersions.auto, + size: 200.0, + gapless: true, + ), StreamBuilder( stream: appData.socket?.stream, builder: (context, snapshot) { @@ -111,15 +117,25 @@ class _HiveAuthLoginScreenState extends State { switch (cmd) { case "auth_wait": var uuid = asString(map, 'uuid'); - var qr = json.encode({ + var qr = base64.encode(utf8.encode(json.encode({ "account": username, "uuid": uuid, "key": authKey, "host": Communicator.hiveAuthServer - }); - setState(() { - this.qrString = qr; - }); + }))); + qr = "has://auth_req/$qr"; + server.updateHiveUserData( + HiveUserData( + username: username, + postingKey: appData.postingKey, + keychainData: appData.keychainData, + cookie: appData.cookie, + resolution: appData.resolution, + rpc: appData.rpc, + socket: appData.socket, + hiveAuthLoginQR: qr, + ), + ); break; default: log('Default case here'); diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 0632541c..46abd244 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -1,7 +1,6 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/login/ha_login_screen.dart'; import 'package:acela/src/utils/communicator.dart'; @@ -10,7 +9,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:provider/provider.dart'; -import 'package:url_launcher/url_launcher.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({Key? key}) : super(key: key); @@ -21,7 +19,6 @@ class LoginScreen extends StatefulWidget { class _LoginScreenState extends State { var isLoading = false; - static const platform = MethodChannel('com.example.acela/auth'); var username = ''; var postingKey = ''; @@ -55,6 +52,7 @@ class _LoginScreenState extends State { resolution: resolution, rpc: rpc, socket: appData.socket, + hiveAuthLoginQR: appData.hiveAuthLoginQR, ), ); Navigator.of(context).pop(); diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index d996160e..479af25a 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -32,6 +32,7 @@ class _AccountSettingsScreenState extends State { resolution: resolution, rpc: rpc, socket: data.socket, + hiveAuthLoginQR: data.hiveAuthLoginQR, ), ); Navigator.of(context).pop(); diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index a670b151..f24be839 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -70,6 +70,7 @@ class _SettingsScreenState extends State { ) : null, socket: appData.socket, + hiveAuthLoginQR: appData.hiveAuthLoginQR, ), ); loadRes(); @@ -133,6 +134,7 @@ class _SettingsScreenState extends State { resolution: user.resolution, rpc: serverUrl, socket: user.socket, + hiveAuthLoginQR: user.hiveAuthLoginQR, ), ); }, diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 6e54f24a..6a466206 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -206,7 +206,8 @@ class Communicator { cookie: cookie, resolution: resolution, rpc: rpc, - socket: user.socket + socket: user.socket, + hiveAuthLoginQR: user.hiveAuthLoginQR, ); server.updateHiveUserData(newData); return cookie; @@ -241,6 +242,7 @@ class Communicator { resolution: resolution, rpc: rpc, socket: user.socket, + hiveAuthLoginQR: user.hiveAuthLoginQR, ); server.updateHiveUserData(newData); return await getValidCookie(newData); diff --git a/pubspec.lock b/pubspec.lock index e303d2e7..f2a66c55 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -889,6 +889,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + pretty_qr_code: + dependency: "direct main" + description: + name: pretty_qr_code + sha256: "9ce7e61f812d3c990262f6bd0b4bfda3d8ef55ce0debb4e6929f5730ac40e40a" + url: "https://pub.dev" + source: hosted + version: "2.0.2" process: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f3952161..9de9acc3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -74,6 +74,7 @@ dependencies: web_socket_channel: ^2.3.0 encryptor: ^0.0.1 qr_flutter: ^4.0.0 + pretty_qr_code: ^2.0.2 dev_dependencies: flutter_test: From 96aefa09ca8038e127c1158bd948df1183a675a5 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 27 Jan 2023 18:03:27 +0530 Subject: [PATCH 157/466] Dart native hive keychain. --- .flutter-plugins-dependencies | 2 +- ios/Runner/AcelaWebViewController.swift | 11 ++ ios/Runner/Bridges/Auth/HASBridge.swift | 135 +++++++++------ ios/Runner/public/index.html | 24 +++ lib/main.dart | 16 +- .../models/user_stream/hive_user_stream.dart | 34 +++- lib/src/screens/login/ha_login_screen.dart | 162 +++++++++++------- lib/src/screens/login/login_screen.dart | 8 +- .../account_settings_screen.dart | 3 +- lib/src/screens/settings/settings_screen.dart | 6 +- lib/src/utils/communicator.dart | 6 +- 11 files changed, 253 insertions(+), 154 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index aea09e6e..5cb0ce8f 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-27 00:12:49.041375","version":"3.7.0-1.5.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-27 17:55:14.844484","version":"3.7.0-1.5.pre"} \ No newline at end of file diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index 999f76eb..2d6016e6 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -19,6 +19,7 @@ class AcelaWebViewController: UIViewController { var postVideoHandler: ((String) -> Void)? var getRedirectUriHandler: ((String) -> Void)? = nil + var getRedirectUriDataHandler: ((String) -> Void)? = nil var hiveUserInfoHandler: ((String) -> Void)? = nil override func viewDidLoad() { @@ -88,6 +89,11 @@ class AcelaWebViewController: UIViewController { webView?.evaluateJavaScript("getRedirectUri('\(username)');") } + func getRedirectUriData(_ username: String, handler: @escaping (String) -> Void) { + getRedirectUriDataHandler = handler + webView?.evaluateJavaScript("getRedirectUriData('\(username)');") + } + func getUserInfo(_ handler: @escaping (String) -> Void) { hiveUserInfoHandler = handler webView?.evaluateJavaScript("getUserInfo();") @@ -150,6 +156,11 @@ extension AcelaWebViewController: WKScriptMessageHandler { let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) else { return } getRedirectUriHandler?(response) + case "getRedirectUriData": + guard + let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) + else { return } + getRedirectUriDataHandler?(response) default: debugPrint("Do nothing here.") } } diff --git a/ios/Runner/Bridges/Auth/HASBridge.swift b/ios/Runner/Bridges/Auth/HASBridge.swift index 0b13f3f5..d2078583 100644 --- a/ios/Runner/Bridges/Auth/HASBridge.swift +++ b/ios/Runner/Bridges/Auth/HASBridge.swift @@ -10,63 +10,88 @@ import UIKit import Flutter class HASBridge { - var window: UIWindow? - var acela: AcelaWebViewController? + var window: UIWindow? + var acela: AcelaWebViewController? - func initiate( - controller: FlutterViewController, - window: UIWindow?, - acela: AcelaWebViewController? - ) { - self.window = window - self.acela = acela - let authChannel = FlutterMethodChannel( - name: "blog.hive.auth/bridge", - binaryMessenger: controller.binaryMessenger - ) + func initiate( + controller: FlutterViewController, + window: UIWindow?, + acela: AcelaWebViewController? + ) { + self.window = window + self.acela = acela + let authChannel = FlutterMethodChannel( + name: "blog.hive.auth/bridge", + binaryMessenger: controller.binaryMessenger + ) - authChannel.setMethodCallHandler({ - [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in - // Note: this method is invoked on the UI thread. - switch (call.method) { - case "getRedirectUri": - guard - let arguments = call.arguments as? NSDictionary, - let username = arguments ["username"] as? String - else { - result(FlutterMethodNotImplemented) - return - } - self?.getRedirectUri(username: username, result: result) - case "getUserInfo": - self?.getUserInfo(result: result) - default: - result(FlutterMethodNotImplemented) - } - }) - } + authChannel.setMethodCallHandler({ + [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + // Note: this method is invoked on the UI thread. + debugPrint("In here - setMethodCallHandler") + debugPrint("Method - \(call.method)") + switch (call.method) { + case "getRedirectUri": + guard + let arguments = call.arguments as? NSDictionary, + let username = arguments ["username"] as? String + else { + result(FlutterMethodNotImplemented) + return + } + self?.getRedirectUri(username: username, result: result) + case "getRedirectUriData": + debugPrint("In case - getRedirectUriData") + guard + let arguments = call.arguments as? NSDictionary, + let username = arguments ["username"] as? String + else { + result(FlutterMethodNotImplemented) + return + } + self?.getRedirectUriData(username: username, result: result) + case "getUserInfo": + self?.getUserInfo(result: result) + default: + result(FlutterMethodNotImplemented) + } + }) + } - private func getUserInfo(result: @escaping FlutterResult) { - guard let acela = acela else { - result(FlutterError(code: "ERROR", - message: "Error setting up Hive", - details: nil)) - return - } - acela.getUserInfo { string in - result(string) - } - } + private func getUserInfo(result: @escaping FlutterResult) { + guard let acela = acela else { + result(FlutterError(code: "ERROR", + message: "Error setting up Hive", + details: nil)) + return + } + acela.getUserInfo { string in + result(string) + } + } - private func getRedirectUri(username: String, result: @escaping FlutterResult) { - guard let acela = acela else { - result(FlutterError(code: "ERROR", - message: "Error setting up Hive", - details: nil)) - return - } - acela.getRedirectUri(username) { string in - result(string) - } - } + private func getRedirectUri(username: String, result: @escaping FlutterResult) { + guard let acela = acela else { + result(FlutterError(code: "ERROR", + message: "Error setting up Hive", + details: nil)) + return + } + acela.getRedirectUri(username) { string in + result(string) + } + } + + private func getRedirectUriData(username: String, result: @escaping FlutterResult) { + guard let acela = acela else { + result(FlutterError(code: "ERROR", + message: "Error setting up Hive", + details: nil)) + return + } + acela.getRedirectUriData(username) { string in + debugPrint("Sending string back - \(string)") + result(string) + } + } } diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index ee043453..33f159ce 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -537,6 +537,30 @@ const payload = { cmd: "auth_req", account: username, data: data }; ws.send(JSON.stringify(payload)); } + + function getRedirectUriData(uname) { + username = uname.toLowerCase(); + const auth_data = { + app: HAS_APP_DATA, + token: undefined, + challenge: undefined, + }; + auth_key = uuidv4(); + const data = CryptoJS.AES.encrypt( + JSON.stringify(auth_data), + auth_key + ).toString(); + const payload = { data: data, authKey: auth_key }; + const payloadData = JSON.stringify(payload); + replyToNative({ + type: "getRedirectUriData", + valid: true, + username: uname, + error: "", + data: payloadData, + }); + } + function click_logout() { username = undefined; token = undefined; diff --git a/lib/main.dart b/lib/main.dart index cca6829a..ccf78207 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,18 +1,12 @@ -import 'dart:io'; - import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; -import 'package:acela/src/utils/communicator.dart'; -// import 'package:firebase_core/firebase_core.dart'; -// import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:overlay_support/overlay_support.dart'; import 'package:provider/provider.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; Future main() async { await dotenv.load(fileName: ".env"); @@ -29,10 +23,6 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { late final Future _futureToLoadData; - WebSocketChannel socket = WebSocketChannel.connect( - Uri.parse(Communicator.hiveAuthServer), - ); - // late final FirebaseMessaging _messaging; // Create storage @@ -73,8 +63,7 @@ class _MyAppState extends State { postingKey: null, username: null, rpc: 'api.hive.blog', - socket: socket, - hiveAuthLoginQR: null, + socketData: null, ), child: StreamProvider.value( value: server.theme, @@ -121,8 +110,7 @@ class _MyAppState extends State { cookie: cookie, resolution: resolution, rpc: rpc, - socket: socket, - hiveAuthLoginQR: null, + socketData: null, ), ); } diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index 2bcbb170..c648bdc9 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -1,3 +1,4 @@ +import 'package:uuid/uuid.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; class HiveKeychainData { @@ -10,6 +11,33 @@ class HiveKeychainData { required this.hasAuthKey, }); } + +class HiveSocketData { + WebSocketChannel? channel; + String? hiveAuthQr; + bool isLoadingQr; + final appData = { + "name": "3Speak Mobile iOS App", + "description": "3Speak Mobile iOS App with HAS Integration", + }; + String? appKey; + String? authUuid; + String? authKey; + String? token; + String? expire; + + HiveSocketData({ + required this.channel, + required this.hiveAuthQr, + required this.isLoadingQr, + required this.appKey, + required this.authUuid, + required this.authKey, + required this.token, + required this.expire, + }); +} + class HiveUserData { String? username; String? postingKey; @@ -17,8 +45,7 @@ class HiveUserData { HiveKeychainData? keychainData; String resolution; String rpc; - WebSocketChannel? socket; - String? hiveAuthLoginQR; + HiveSocketData? socketData; HiveUserData({ required this.username, @@ -27,7 +54,6 @@ class HiveUserData { required this.cookie, required this.resolution, required this.rpc, - required this.socket, - required this.hiveAuthLoginQR, + required this.socketData, }); } diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index b47172bd..477edf52 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -2,41 +2,42 @@ import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/safe_convert.dart'; import 'package:encryptor/encryptor.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:pretty_qr_code/pretty_qr_code.dart'; import 'package:provider/provider.dart'; import 'package:qr_flutter/qr_flutter.dart'; +import 'package:url_launcher/url_launcher.dart'; import 'package:uuid/uuid.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; class HiveAuthLoginScreen extends StatefulWidget { - const HiveAuthLoginScreen({Key? key}) : super(key: key); + const HiveAuthLoginScreen({ + Key? key, + required this.appData, + }) : super(key: key); + final HiveUserData appData; @override State createState() => _HiveAuthLoginScreenState(); } class _HiveAuthLoginScreenState extends State { - var isLoading = false; - var username = ''; - var appData = { - "name": "3Speak Mobile iOS App", - "description": "3Speak Mobile iOS App with HAS Integration", - }; - var appKey = Uuid().v4(); - String? authUuid; - String? authKey; - String? token; - String? expire; - static const platform = MethodChannel('com.example.acela/auth'); + static const platform = MethodChannel('blog.hive.auth/bridge'); + var usernameController = TextEditingController(); + late WebSocketChannel socket; + String authKey = ""; @override void initState() { super.initState(); + socket = WebSocketChannel.connect( + Uri.parse(Communicator.hiveAuthServer), + ); } void showError(String string) { @@ -52,38 +53,34 @@ class _HiveAuthLoginScreenState extends State { hintText: 'Enter Hive username here', ), autocorrect: false, - onChanged: (value) { - setState(() { - username = value; - }); - }, - enabled: isLoading ? false : true, + controller: usernameController, ); } Widget _hasButton(HiveUserData data) { return ElevatedButton( onPressed: () async { - if (username.isEmpty) return; - setState(() { - // isLoading = true; - authKey = Uuid().v4(); - if (authKey == null) return; - var authData = { - "app": appData, - // "token": token, - // "challenge": null, - }; - var jsonString = json.encode(authData); - var encrypted = Encryptor.encrypt(authKey!, jsonString); - var payload = { + if (usernameController.text.isEmpty) return; + final String response = + await platform.invokeMethod('getRedirectUriData', { + 'username': usernameController.text, + }); + var bridgeResponse = LoginBridgeResponse.fromJsonString(response); + if (bridgeResponse.data != null) { + var data = json.decode(bridgeResponse.data!) as Map; + var dataForSocket = asString(data, 'data'); + var key = asString(data, 'authKey'); + var socketData = { "cmd": "auth_req", - "account": username, - "data": encrypted, + "account": usernameController.text, + "data": dataForSocket, }; - var payloadJsonString = json.encode(payload); - data.socket?.sink.add(payloadJsonString); - }); + var jsonEncodedData = json.encode(socketData); + socket.sink.add(jsonEncodedData); + setState(() { + authKey = key; + }); + } }, child: const Text('Log in with Hive Auth'), ); @@ -96,18 +93,8 @@ class _HiveAuthLoginScreenState extends State { children: [ _hiveUserName(), SizedBox(height: 20), - isLoading - ? CircularProgressIndicator() - : appData.hiveAuthLoginQR == null - ? _hasButton(appData) - : QrImage( - data: appData.hiveAuthLoginQR!, - // version: QrVersions.auto, - size: 200.0, - gapless: true, - ), StreamBuilder( - stream: appData.socket?.stream, + stream: socket.stream, builder: (context, snapshot) { var data = snapshot.data as String?; if (snapshot.hasData && data != null && data.isNotEmpty == true) { @@ -117,28 +104,69 @@ class _HiveAuthLoginScreenState extends State { switch (cmd) { case "auth_wait": var uuid = asString(map, 'uuid'); - var qr = base64.encode(utf8.encode(json.encode({ - "account": username, + var jsonData = { + "account": usernameController.text, "uuid": uuid, "key": authKey, "host": Communicator.hiveAuthServer - }))); + }; + var jsonString = json.encode(jsonData); + var utf8Data = utf8.encode(jsonString); + var qr = base64.encode(utf8Data); qr = "has://auth_req/$qr"; - server.updateHiveUserData( - HiveUserData( - username: username, - postingKey: appData.postingKey, - keychainData: appData.keychainData, - cookie: appData.cookie, - resolution: appData.resolution, - rpc: appData.rpc, - socket: appData.socket, - hiveAuthLoginQR: qr, - ), + return Column( + children: [ + Text('Scan QR Code'), + SizedBox(height: 10), + Container( + decoration: BoxDecoration(color: Colors.white), + child: QrImage( + data: qr, + size: 200.0, + gapless: true, + ), + ), + SizedBox(height: 10), + Text('- OR -'), + SizedBox(height: 10), + Text('Launch HiveKeychain App'), + SizedBox(height: 20), + ElevatedButton( + onPressed: () { + var url = Uri.parse(qr); + launchUrl(url); + }, + child: + Image.asset('assets/hive-keychain-image.png'), + ), + ], ); - break; + case "auth_ack": + var messageData = asString(map, 'data'); + var decrypted = Encryptor.encrypt(authKey, messageData); + var decodedData = + json.decode(decrypted) as Map; + var token = asString(decodedData, 'token'); + var expire = asString(decodedData, 'expire'); + return Text('Token: $token\nExpire: $expire'); + case "auth_nack": + return Text("Auth was not acknowledged"); + case "sign_wait": + var uuid = asString(map, 'uuid'); + return Text( + "Transaction - $uuid is waiting for approval."); + case "sign_ack": + var uuid = asString(map, 'uuid'); + return Text("Transaction - $uuid is was approved."); + case "sign_nack": + var uuid = asString(map, 'uuid'); + return Text("Transaction - $uuid is was declined."); + case "sign_err": + var uuid = asString(map, 'uuid'); + return Text("Transaction - $uuid failed."); default: log('Default case here'); + return _hasButton(appData); } } } @@ -150,6 +178,12 @@ class _HiveAuthLoginScreenState extends State { ); } + @override + void dispose() { + super.dispose(); + socket.sink.close(); + } + @override Widget build(BuildContext context) { var data = Provider.of(context); diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 46abd244..9a83f4cb 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -1,12 +1,9 @@ -import 'dart:developer'; - import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/login/ha_login_screen.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/crypto_manager.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:provider/provider.dart'; @@ -51,8 +48,7 @@ class _LoginScreenState extends State { cookie: null, resolution: resolution, rpc: rpc, - socket: appData.socket, - hiveAuthLoginQR: appData.hiveAuthLoginQR, + socketData: appData.socketData, ), ); Navigator.of(context).pop(); @@ -156,7 +152,7 @@ class _LoginScreenState extends State { ), IconButton( onPressed: () { - const screen = HiveAuthLoginScreen(); + var screen = HiveAuthLoginScreen(appData: data); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); }, diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index 479af25a..c78780f5 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -31,8 +31,7 @@ class _AccountSettingsScreenState extends State { cookie: null, resolution: resolution, rpc: rpc, - socket: data.socket, - hiveAuthLoginQR: data.hiveAuthLoginQR, + socketData: data.socketData, ), ); Navigator.of(context).pop(); diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index f24be839..d14ecb39 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -69,8 +69,7 @@ class _SettingsScreenState extends State { hasId: hasId, ) : null, - socket: appData.socket, - hiveAuthLoginQR: appData.hiveAuthLoginQR, + socketData: appData.socketData, ), ); loadRes(); @@ -133,8 +132,7 @@ class _SettingsScreenState extends State { cookie: user.cookie, resolution: user.resolution, rpc: serverUrl, - socket: user.socket, - hiveAuthLoginQR: user.hiveAuthLoginQR, + socketData: user.socketData, ), ); }, diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 6a466206..850991e7 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -206,8 +206,7 @@ class Communicator { cookie: cookie, resolution: resolution, rpc: rpc, - socket: user.socket, - hiveAuthLoginQR: user.hiveAuthLoginQR, + socketData: user.socketData, ); server.updateHiveUserData(newData); return cookie; @@ -241,8 +240,7 @@ class Communicator { cookie: null, resolution: resolution, rpc: rpc, - socket: user.socket, - hiveAuthLoginQR: user.hiveAuthLoginQR, + socketData: user.socketData, ); server.updateHiveUserData(newData); return await getValidCookie(newData); From 7c6e149710daa1a52340112465c7c2b312c65701 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sat, 28 Jan 2023 19:00:21 +0530 Subject: [PATCH 158/466] socket work working. --- .flutter-plugins-dependencies | 2 +- ios/Runner/AcelaWebViewController.swift | 16 ++ ios/Runner/Bridges/Auth/HASBridge.swift | 26 +- ios/Runner/public/index.html | 25 ++ lib/main.dart | 2 - .../models/user_stream/hive_user_stream.dart | 27 +- .../screens/drawer_screen/drawer_screen.dart | 54 ++-- lib/src/screens/login/ha_login_screen.dart | 247 +++++++++++------- lib/src/screens/login/login_screen.dart | 1 - .../account_settings_screen.dart | 1 - lib/src/screens/settings/settings_screen.dart | 2 - lib/src/utils/communicator.dart | 2 - 12 files changed, 252 insertions(+), 153 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 5cb0ce8f..6e358c0f 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-27 17:55:14.844484","version":"3.7.0-1.5.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-01-28 18:37:09.663479","version":"3.7.0-1.5.pre"} \ No newline at end of file diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index 2d6016e6..72dbc7cd 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -21,6 +21,7 @@ class AcelaWebViewController: UIViewController { var getRedirectUriHandler: ((String) -> Void)? = nil var getRedirectUriDataHandler: ((String) -> Void)? = nil var hiveUserInfoHandler: ((String) -> Void)? = nil + var getDecryptedHASTokenHandler: ((String) -> Void)? = nil override func viewDidLoad() { super.viewDidLoad() @@ -94,6 +95,16 @@ class AcelaWebViewController: UIViewController { webView?.evaluateJavaScript("getRedirectUriData('\(username)');") } + func getDecryptedHASToken( + username: String, + authKey: String, + data: String, + handler: @escaping (String) -> Void + ) { + getDecryptedHASTokenHandler = handler + webView?.evaluateJavaScript("getDecryptedHASToken('\(username)','\(authKey)','\(data)');") + } + func getUserInfo(_ handler: @escaping (String) -> Void) { hiveUserInfoHandler = handler webView?.evaluateJavaScript("getUserInfo();") @@ -161,6 +172,11 @@ extension AcelaWebViewController: WKScriptMessageHandler { let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) else { return } getRedirectUriDataHandler?(response) + case "getDecryptedHASToken": + guard + let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) + else { return } + getDecryptedHASTokenHandler?(response) default: debugPrint("Do nothing here.") } } diff --git a/ios/Runner/Bridges/Auth/HASBridge.swift b/ios/Runner/Bridges/Auth/HASBridge.swift index d2078583..80466e5e 100644 --- a/ios/Runner/Bridges/Auth/HASBridge.swift +++ b/ios/Runner/Bridges/Auth/HASBridge.swift @@ -28,8 +28,6 @@ class HASBridge { authChannel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in // Note: this method is invoked on the UI thread. - debugPrint("In here - setMethodCallHandler") - debugPrint("Method - \(call.method)") switch (call.method) { case "getRedirectUri": guard @@ -41,7 +39,6 @@ class HASBridge { } self?.getRedirectUri(username: username, result: result) case "getRedirectUriData": - debugPrint("In case - getRedirectUriData") guard let arguments = call.arguments as? NSDictionary, let username = arguments ["username"] as? String @@ -50,6 +47,17 @@ class HASBridge { return } self?.getRedirectUriData(username: username, result: result) + case "getDecryptedHASToken": + guard + let arguments = call.arguments as? NSDictionary, + let username = arguments ["username"] as? String, + let authKey = arguments ["authKey"] as? String, + let data = arguments ["data"] as? String + else { + result(FlutterMethodNotImplemented) + return + } + self?.getDecryptedHASToken(username: username, authKey: authKey, data: data, result: result) case "getUserInfo": self?.getUserInfo(result: result) default: @@ -58,6 +66,18 @@ class HASBridge { }) } + private func getDecryptedHASToken(username: String, authKey: String, data: String, result: @escaping FlutterResult) { + guard let acela = acela else { + result(FlutterError(code: "ERROR", + message: "Error setting up Hive", + details: nil)) + return + } + acela.getDecryptedHASToken(username: username, authKey: authKey, data: data) { string in + result(string) + } + } + private func getUserInfo(result: @escaping FlutterResult) { guard let acela = acela else { result(FlutterError(code: "ERROR", diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index 33f159ce..f60a7521 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -561,6 +561,31 @@ }); } + function getDecryptedHASToken(username, authKey, data) { + try { + // Try to decrypt and parse payload data + const decryptedData = JSON.parse( + CryptoJS.AES.decrypt(data, authKey).toString(CryptoJS.enc.Utf8) + ); + const token = decryptedData.token; + const expire = decryptedData.expire; + replyToNative({ + type: "getDecryptedHASToken", + valid: true, + username: username, + error: "", + data: `${token},${expire}`, + }); + } catch (e) { + replyToNative({ + type: "getDecryptedHASToken", + valid: false, + accountName: username, + error: e.message, + }); + } + } + function click_logout() { username = undefined; token = undefined; diff --git a/lib/main.dart b/lib/main.dart index ccf78207..80c4f9d3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -63,7 +63,6 @@ class _MyAppState extends State { postingKey: null, username: null, rpc: 'api.hive.blog', - socketData: null, ), child: StreamProvider.value( value: server.theme, @@ -110,7 +109,6 @@ class _MyAppState extends State { cookie: cookie, resolution: resolution, rpc: rpc, - socketData: null, ), ); } diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index c648bdc9..d60cb0ab 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -1,6 +1,3 @@ -import 'package:uuid/uuid.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; - class HiveKeychainData { String hasId; String hasExpiry; @@ -13,28 +10,12 @@ class HiveKeychainData { } class HiveSocketData { - WebSocketChannel? channel; - String? hiveAuthQr; - bool isLoadingQr; - final appData = { - "name": "3Speak Mobile iOS App", - "description": "3Speak Mobile iOS App with HAS Integration", - }; - String? appKey; - String? authUuid; - String? authKey; - String? token; - String? expire; + String authKey; + String encryptedData; HiveSocketData({ - required this.channel, - required this.hiveAuthQr, - required this.isLoadingQr, - required this.appKey, - required this.authUuid, required this.authKey, - required this.token, - required this.expire, + required this.encryptedData, }); } @@ -45,7 +26,6 @@ class HiveUserData { HiveKeychainData? keychainData; String resolution; String rpc; - HiveSocketData? socketData; HiveUserData({ required this.username, @@ -54,6 +34,5 @@ class HiveUserData { required this.cookie, required this.resolution, required this.rpc, - required this.socketData, }); } diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index 44a0d7e5..e2174a0d 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -207,32 +207,34 @@ class DrawerScreen extends StatelessWidget { Widget _drawerMenu(BuildContext context) { var user = Provider.of(context); - return ListView( - children: [ - _drawerHeader(context), - _homeMenu(context), - _divider(), - _firstUploads(context), - _divider(), - _trendingContent(context), - _divider(), - _newContent(context), - _divider(), - _communities(context), - _divider(), - _leaderBoard(context), - _divider(), - _shorts(context), - _divider(), - _settings(context), - _divider(), - user.username == null ? _login(context) : _myAccount(context), - _divider(), - _importantLinks(context), - _divider(), - _desktopApp(), - _divider(), - ], + return SafeArea( + child: ListView( + children: [ + _drawerHeader(context), + _homeMenu(context), + _divider(), + _firstUploads(context), + _divider(), + _trendingContent(context), + _divider(), + _newContent(context), + _divider(), + _communities(context), + _divider(), + _leaderBoard(context), + _divider(), + _shorts(context), + _divider(), + _settings(context), + _divider(), + user.username == null ? _login(context) : _myAccount(context), + _divider(), + _importantLinks(context), + _divider(), + _desktopApp(), + _divider(), + ], + ), ); } diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index 477edf52..79ab1292 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:developer'; @@ -6,9 +7,9 @@ import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/safe_convert.dart'; -import 'package:encryptor/encryptor.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:provider/provider.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -30,7 +31,10 @@ class _HiveAuthLoginScreenState extends State { static const platform = MethodChannel('blog.hive.auth/bridge'); var usernameController = TextEditingController(); late WebSocketChannel socket; - String authKey = ""; + String authKey = ''; + String username = ''; + String? qrCode; + var loadingQR = false; @override void initState() { @@ -38,6 +42,57 @@ class _HiveAuthLoginScreenState extends State { socket = WebSocketChannel.connect( Uri.parse(Communicator.hiveAuthServer), ); + socket.stream.listen((message) { + var map = json.decode(message) as Map; + var cmd = asString(map, 'cmd'); + if (cmd.isNotEmpty) { + switch (cmd) { + case "auth_wait": + var uuid = asString(map, 'uuid'); + var jsonData = { + "account": usernameController.text, + "uuid": uuid, + "key": authKey, + "host": Communicator.hiveAuthServer + }; + var jsonString = json.encode(jsonData); + var utf8Data = utf8.encode(jsonString); + var qr = base64.encode(utf8Data); + qr = "has://auth_req/$qr"; + setState(() { + qrCode = qr; + loadingQR = false; + }); + break; + case "auth_ack": + var messageData = asString(map, 'data'); + decryptData(widget.appData, messageData); + break; + case "auth_nack": + showError("Auth was not acknowledged"); + setState(() { + qrCode = null; + loadingQR = false; + }); + break; + // case "sign_wait": + // var uuid = asString(map, 'uuid'); + // return Text( + // "Transaction - $uuid is waiting for approval."); + // case "sign_ack": + // var uuid = asString(map, 'uuid'); + // return Text("Transaction - $uuid is was approved."); + // case "sign_nack": + // var uuid = asString(map, 'uuid'); + // return Text("Transaction - $uuid is was declined."); + // case "sign_err": + // var uuid = asString(map, 'uuid'); + // return Text("Transaction - $uuid failed."); + default: + log('Default case here'); + } + } + }); } void showError(String string) { @@ -45,6 +100,11 @@ class _HiveAuthLoginScreenState extends State { ScaffoldMessenger.of(context).showSnackBar(snackBar); } + void showMessage(String string) { + var snackBar = SnackBar(content: Text(string)); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + Widget _hiveUserName() { return TextField( decoration: InputDecoration( @@ -79,6 +139,7 @@ class _HiveAuthLoginScreenState extends State { socket.sink.add(jsonEncodedData); setState(() { authKey = key; + username = usernameController.text; }); } }, @@ -86,104 +147,108 @@ class _HiveAuthLoginScreenState extends State { ); } - Widget _loginForm(HiveUserData appData) { - return Container( - margin: EdgeInsets.all(10), - child: Column( - children: [ - _hiveUserName(), - SizedBox(height: 20), - StreamBuilder( - stream: socket.stream, - builder: (context, snapshot) { - var data = snapshot.data as String?; - if (snapshot.hasData && data != null && data.isNotEmpty == true) { - var map = json.decode(data) as Map; - var cmd = asString(map, 'cmd'); - if (cmd.isNotEmpty) { - switch (cmd) { - case "auth_wait": - var uuid = asString(map, 'uuid'); - var jsonData = { - "account": usernameController.text, - "uuid": uuid, - "key": authKey, - "host": Communicator.hiveAuthServer - }; - var jsonString = json.encode(jsonData); - var utf8Data = utf8.encode(jsonString); - var qr = base64.encode(utf8Data); - qr = "has://auth_req/$qr"; - return Column( - children: [ - Text('Scan QR Code'), - SizedBox(height: 10), - Container( - decoration: BoxDecoration(color: Colors.white), - child: QrImage( - data: qr, - size: 200.0, - gapless: true, - ), - ), - SizedBox(height: 10), - Text('- OR -'), - SizedBox(height: 10), - Text('Launch HiveKeychain App'), - SizedBox(height: 20), - ElevatedButton( - onPressed: () { - var url = Uri.parse(qr); - launchUrl(url); - }, - child: - Image.asset('assets/hive-keychain-image.png'), - ), - ], - ); - case "auth_ack": - var messageData = asString(map, 'data'); - var decrypted = Encryptor.encrypt(authKey, messageData); - var decodedData = - json.decode(decrypted) as Map; - var token = asString(decodedData, 'token'); - var expire = asString(decodedData, 'expire'); - return Text('Token: $token\nExpire: $expire'); - case "auth_nack": - return Text("Auth was not acknowledged"); - case "sign_wait": - var uuid = asString(map, 'uuid'); - return Text( - "Transaction - $uuid is waiting for approval."); - case "sign_ack": - var uuid = asString(map, 'uuid'); - return Text("Transaction - $uuid is was approved."); - case "sign_nack": - var uuid = asString(map, 'uuid'); - return Text("Transaction - $uuid is was declined."); - case "sign_err": - var uuid = asString(map, 'uuid'); - return Text("Transaction - $uuid failed."); - default: - log('Default case here'); - return _hasButton(appData); - } - } - } - return Container(); - }, - ) - ], - ), + Widget _showQRCodeAndKeychainButton(String qr) { + return Column( + children: [ + Text('Scan QR Code'), + SizedBox(height: 10), + Container( + decoration: BoxDecoration(color: Colors.white), + child: QrImage( + data: qr, + size: 200.0, + gapless: true, + ), + ), + SizedBox(height: 10), + Text('- OR -'), + SizedBox(height: 10), + Text('Launch HiveKeychain App'), + SizedBox(height: 20), + ElevatedButton( + onPressed: () { + var url = Uri.parse(qr); + launchUrl(url); + }, + child: Image.asset('assets/hive-keychain-image.png'), + ), + ], ); } + Widget _loginForm(HiveUserData appData) { + return loadingQR + ? const Center(child: CircularProgressIndicator()) + : qrCode == null + ? Container( + margin: EdgeInsets.all(10), + child: Column( + children: [ + _hiveUserName(), + SizedBox(height: 20), + _hasButton(appData) + ], + ), + ) + : _showQRCodeAndKeychainButton(qrCode!); + } + @override void dispose() { super.dispose(); socket.sink.close(); } + void decryptData(HiveUserData data, String encryptedData) async { + final String response = + await platform.invokeMethod('getDecryptedHASToken', { + 'username': username, + 'authKey': authKey, + 'data': encryptedData, + }); + var bridgeResponse = LoginBridgeResponse.fromJsonString(response); + if (bridgeResponse.valid && + bridgeResponse.data != null && + bridgeResponse.data!.isNotEmpty) { + var tokenData = bridgeResponse.data!.split(","); + if (tokenData.isEmpty || tokenData.length != 2) { + showMessage( + 'Did not find token & expiry details from HiveAuth. Please go back & try again.'); + } else { + const storage = FlutterSecureStorage(); + await storage.write(key: 'username', value: username); + await storage.delete(key: 'postingKey'); + await storage.delete(key: 'cookie'); + await storage.write(key: 'hasId', value: tokenData[0]); + await storage.write(key: 'hasExpiry', value: tokenData[1]); + await storage.write(key: 'hasAuthKey', value: authKey); + server.updateHiveUserData( + HiveUserData( + username: username, + postingKey: null, + keychainData: HiveKeychainData( + hasAuthKey: authKey, + hasExpiry: tokenData[1], + hasId: tokenData[0], + ), + cookie: null, + resolution: data.resolution, + rpc: data.rpc, + ), + ); + showMessage('You have successfully logged in with Hive Auth with user - $username'); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + } + } else { + showMessage( + 'Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); + } + // Timer(Duration(seconds: 2), () async { + // + // }); + } + @override Widget build(BuildContext context) { var data = Provider.of(context); diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 9a83f4cb..661e6b9a 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -48,7 +48,6 @@ class _LoginScreenState extends State { cookie: null, resolution: resolution, rpc: rpc, - socketData: appData.socketData, ), ); Navigator.of(context).pop(); diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index c78780f5..c88b6aff 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -31,7 +31,6 @@ class _AccountSettingsScreenState extends State { cookie: null, resolution: resolution, rpc: rpc, - socketData: data.socketData, ), ); Navigator.of(context).pop(); diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index d14ecb39..31021fe3 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -69,7 +69,6 @@ class _SettingsScreenState extends State { hasId: hasId, ) : null, - socketData: appData.socketData, ), ); loadRes(); @@ -132,7 +131,6 @@ class _SettingsScreenState extends State { cookie: user.cookie, resolution: user.resolution, rpc: serverUrl, - socketData: user.socketData, ), ); }, diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 850991e7..aeb6327e 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -206,7 +206,6 @@ class Communicator { cookie: cookie, resolution: resolution, rpc: rpc, - socketData: user.socketData, ); server.updateHiveUserData(newData); return cookie; @@ -240,7 +239,6 @@ class Communicator { cookie: null, resolution: resolution, rpc: rpc, - socketData: user.socketData, ); server.updateHiveUserData(newData); return await getValidCookie(newData); From 57ce065ab382122a9dfa120aa1033a7e82e75c27 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 31 Jan 2023 18:35:06 +0530 Subject: [PATCH 159/466] HiveAuth based posting in progress. --- ios/Runner/public/index.html | 230 ++---------------- lib/src/screens/login/ha_login_screen.dart | 26 +- .../update_video/video_details_info.dart | 44 +++- 3 files changed, 84 insertions(+), 216 deletions(-) diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index f60a7521..d72c0a0c 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -362,33 +362,36 @@ JSON.stringify(sign_data), hasAuthKey ).toString(); - const payload = { - cmd: "sign_req", - account: author, - token: hasKey, + // const payload = { + // cmd: "sign_req", + // account: author, + // token: hasKey, + // data: data, + // }; + replyToNative({ + type: "postVideo", + valid: true, + username: author, + error: "", data: data, - }; - ws.send(JSON.stringify(payload)); + }); } else { tryPublish(operations, postingKey) .then((result) => { - var newResult = { + replyToNative({ type: "postVideo", valid: true, - error: "success", - }; - window.webkit.messageHandlers.acela.postMessage(newResult); - //Android.postMessage(JSON.stringify(newResult)); + username: author, + }); }) .catch((error) => { console.error(error); - var result = { + replyToNative({ type: "postVideo", valid: false, - error: error.message, - }; - window.webkit.messageHandlers.acela.postMessage(result); - //Android.postMessage(JSON.stringify(result)); + username: author, + error: error.message + }); }); } }) @@ -403,140 +406,6 @@ //Android.postMessage(JSON.stringify(result)); }); } - - - - + + + - + diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index 71d9baab..d146cd2d 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -181,21 +181,6 @@ class _HiveAuthLoginScreenState extends State semanticsLabel: 'Timeout Timer for HiveAuth QR', ), ), - SizedBox(height: 20), - Text('- OR -'), - SizedBox(height: 20), - ElevatedButton( - onPressed: () { - var url = Uri.parse(qr); - launchUrl(url); - }, - child: Image.asset('assets/hive-keychain-image.png'), - ), - SizedBox(height: 10), - Text( - 'Launch "Keychain For Hive" app & authorize.\n\nNOTE: Launching "Keychain for Hive" app, only works on mobile devices.', - textAlign: TextAlign.center, - ), ], ), ); diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 661e6b9a..208d7434 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -149,14 +149,14 @@ class _LoginScreenState extends State { }, icon: Icon(Icons.help), ), - IconButton( - onPressed: () { - var screen = HiveAuthLoginScreen(appData: data); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - icon: Image.asset('assets/hiveauth_icon.png'), - ) + // IconButton( + // onPressed: () { + // var screen = HiveAuthLoginScreen(appData: data); + // var route = MaterialPageRoute(builder: (c) => screen); + // Navigator.of(context).push(route); + // }, + // icon: Image.asset('assets/hiveauth_icon.png'), + // ) ], ), body: _loginForm(data), diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index 5446f2b5..1a8495a9 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -49,6 +49,7 @@ class _VideoDetailsInfoState extends State { var selectedCommunityVisibleName = 'Threespeak'; String? hiveKeychainTransactionId; late WebSocketChannel socket; + var socketClosed = true; void showError(String string) { var snackBar = SnackBar(content: Text('Error: $string')); @@ -83,7 +84,7 @@ class _VideoDetailsInfoState extends State { break; case "sign_wait": var uuid = asString(map, 'uuid'); - showMessage("Transaction - $uuid is waiting for approval. Please launch \"Keychain for Hive\" and approve to publish on Hive."); + showDialogForHASTransaction(uuid); break; case "sign_ack": var uuid = asString(map, 'uuid'); @@ -91,8 +92,7 @@ class _VideoDetailsInfoState extends State { isCompleting = false; processText = ''; }); - showMessage( - "Transaction - $uuid was approved. Please hit save button again after 10 seconds to mark video as published."); + showDialogForAfter10Seconds("Transaction - $uuid was approved. Please hit save button again after 10 seconds to mark video as published."); break; case "sign_nack": setState(() { @@ -100,7 +100,8 @@ class _VideoDetailsInfoState extends State { processText = ''; }); var uuid = asString(map, 'uuid'); - showError("Transaction - $uuid was declined. Please hit save button again to try again."); + showError( + "Transaction - $uuid was declined. Please hit save button again to try again."); break; case "sign_err": setState(() { @@ -114,7 +115,17 @@ class _VideoDetailsInfoState extends State { log('Default case here'); } } - }); + }, onError: (e) async { + await Future.delayed(Duration(seconds: 2)); + socket = WebSocketChannel.connect( + Uri.parse(Communicator.hiveAuthServer), + ); + }, onDone: () async { + await Future.delayed(Duration(seconds: 2)); + socket = WebSocketChannel.connect( + Uri.parse(Communicator.hiveAuthServer), + ); + }, cancelOnError: true); } void initiateUpload( @@ -222,7 +233,8 @@ class _VideoDetailsInfoState extends State { showMessage('Congratulations. Your video is published.'); showMyDialog(); }); - } else if (bridgeResponse.error == "" && bridgeResponse.data != null && + } else if (bridgeResponse.error == "" && + bridgeResponse.data != null && user.keychainData?.hasAuthKey != null) { var socketData = { "cmd": "sign_req", @@ -252,6 +264,40 @@ class _VideoDetailsInfoState extends State { } } + void showDialogForAfter10Seconds(String message) { + Widget okButton = TextButton( + child: Text("Okay"), + onPressed: () { + Navigator.of(context).pop(); + }, + ); + AlertDialog alert = AlertDialog( + title: Text("🎉 Congratulations 🎉"), + content: Text(message), + actions: [ + okButton, + ], + ); + showDialog(context: context, builder: (c) => alert); + } + + void showDialogForHASTransaction(String uuid) { + Widget okButton = TextButton( + child: Text("Okay"), + onPressed: () { + Navigator.of(context).pop(); + }, + ); + AlertDialog alert = AlertDialog( + title: Text("Launch HiveAuth / HiveKeychain"), + content: Text("Transaction - $uuid is waiting for approval. Please launch \"Keychain for Hive\" and approve to publish on Hive."), + actions: [ + okButton, + ], + ); + showDialog(context: context, builder: (c) => alert); + } + void showMyDialog() { Widget okButton = TextButton( child: Text("Okay"), @@ -264,7 +310,7 @@ class _VideoDetailsInfoState extends State { ); AlertDialog alert = AlertDialog( title: Text("🎉 Congratulations 🎉"), - content: Text("Your Video is published on Hive."), + content: Text("Your Video is published on Hive & video is marked as published."), actions: [ okButton, ], From 75bcb23f81ac4b8ead45905391b0dc6b08b129f3 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 10 Feb 2023 15:49:13 +0530 Subject: [PATCH 163/466] 2. "Getting/compressing the video" doesn't make sense to me. I don't think you need to log the amount of time someone picks a video. same with "Launching Video picker" 3. "It is also moved to encoding queue" --> "Video has be added to the encoding queue" 4. Maybe change "Your Video is Uploaded" to something like "Your Video is in Progress. --- .flutter-plugins-dependencies | 2 +- lib/src/screens/home_screen/home_screen.dart | 5 +- lib/src/screens/login/ha_login_screen.dart | 246 ++++++++++++++---- lib/src/screens/login/login_screen.dart | 16 +- .../upload/new_video_upload_screen.dart | 36 +-- 5 files changed, 226 insertions(+), 79 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index bcd51241..a14fe528 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-02-07 14:23:22.570021","version":"3.7.0-1.5.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-02-10 15:47:04.822833","version":"3.7.0-1.5.pre"} \ No newline at end of file diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 2365cb69..e40966a2 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -212,11 +212,12 @@ class _HomeScreenState extends State { } Widget _fabNewUpload() { - return FloatingActionButton( + return FloatingActionButton.extended( onPressed: () { showBottomSheetForRecordingTypes(); }, - child: const Icon(Icons.add), + label: const Text('Upload Video'), + icon: const Icon(Icons.upload), ); } diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index d146cd2d..d178c10e 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -6,6 +6,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/utils/crypto_manager.dart'; import 'package:acela/src/utils/safe_convert.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -38,6 +39,11 @@ class _HiveAuthLoginScreenState extends State var timer = 0; var timeoutValue = 0; Timer? ticker; + var didTapKeychainButton = false; + + var isLoading = false; + var postingKey = ''; + static const storage = FlutterSecureStorage(); @override void initState() { @@ -69,6 +75,12 @@ class _HiveAuthLoginScreenState extends State qr = "has://auth_req/$qr"; setState(() { qrCode = qr; + if (didTapKeychainButton) { + var uri = Uri.tryParse(qr); + if (uri != null) { + launchUrl(uri); + } + } timer = timeoutValue; ticker = Timer.periodic(Duration(seconds: 1), (tickrr) { if (timer == 0) { @@ -117,7 +129,7 @@ class _HiveAuthLoginScreenState extends State Widget _hiveUserName() { return TextField( decoration: InputDecoration( - icon: const Icon(Icons.person), + icon: const Icon(Icons.alternate_email_outlined), label: const Text('Hive Username'), hintText: 'Enter Hive username here', ), @@ -126,33 +138,72 @@ class _HiveAuthLoginScreenState extends State ); } + void _hasButtonTapped(bool keychainTapped) async { + if (usernameController.text.isEmpty) return; + setState(() { + loadingQR = true; + }); + final String response = await platform.invokeMethod('getRedirectUriData', { + 'username': usernameController.text, + }); + var bridgeResponse = LoginBridgeResponse.fromJsonString(response); + if (bridgeResponse.data != null) { + var data = json.decode(bridgeResponse.data!) as Map; + var dataForSocket = asString(data, 'data'); + var key = asString(data, 'authKey'); + var socketData = { + "cmd": "auth_req", + "account": usernameController.text, + "data": dataForSocket, + }; + var jsonEncodedData = json.encode(socketData); + socket.sink.add(jsonEncodedData); + setState(() { + didTapKeychainButton = keychainTapped; + authKey = key; + username = usernameController.text; + }); + } + } + Widget _hasButton(HiveUserData data) { - return ElevatedButton( - onPressed: () async { - if (usernameController.text.isEmpty) return; - final String response = - await platform.invokeMethod('getRedirectUriData', { - 'username': usernameController.text, + return Row( + children: [ + const Spacer(), + ElevatedButton( + onPressed: () { + _hasButtonTapped(true); + }, + style: ElevatedButton.styleFrom(backgroundColor: Colors.black), + child: Image.asset('assets/hive-keychain-image.png', width: 120), + ), + const SizedBox(width: 10), + ElevatedButton( + onPressed: () { + _hasButtonTapped(false); + }, + style: ElevatedButton.styleFrom(backgroundColor: Colors.black), + child: Image.asset('assets/hive_auth_button.png', width: 120), + ), + const Spacer(), + ], + ); + } + + Widget _hivePostingKey() { + return TextField( + decoration: InputDecoration( + icon: const Icon(Icons.key), + label: const Text('Hive Posting Key'), + hintText: 'Copy & paste posting key here', + ), + obscureText: true, + onChanged: (value) { + setState(() { + postingKey = value; }); - var bridgeResponse = LoginBridgeResponse.fromJsonString(response); - if (bridgeResponse.data != null) { - var data = json.decode(bridgeResponse.data!) as Map; - var dataForSocket = asString(data, 'data'); - var key = asString(data, 'authKey'); - var socketData = { - "cmd": "auth_req", - "account": usernameController.text, - "data": dataForSocket, - }; - var jsonEncodedData = json.encode(socketData); - socket.sink.add(jsonEncodedData); - setState(() { - authKey = key; - username = usernameController.text; - }); - } }, - child: const Text('Log in with Hive Auth'), + enabled: isLoading ? false : true, ); } @@ -160,34 +211,69 @@ class _HiveAuthLoginScreenState extends State return Center( child: Column( children: [ - const SizedBox(height: 10), - Image.asset('assets/hive_auth_button.png'), - const SizedBox(height: 10), - Text('Scan QR Code'), - SizedBox(height: 10), - Container( - decoration: BoxDecoration(color: Colors.white), - child: QrImage( - data: qr, - size: 200.0, - gapless: true, - ), - ), - SizedBox(height: 10), - SizedBox( - width: 200, - child: LinearProgressIndicator( - value: timer.toDouble() / timeoutValue.toDouble(), - semanticsLabel: 'Timeout Timer for HiveAuth QR', - ), - ), + didTapKeychainButton + ? Container() + : Column( + children: [ + const SizedBox(height: 10), + Image.asset('assets/hive_auth_button.png'), + const SizedBox(height: 10), + Text('Scan QR Code'), + SizedBox(height: 10), + Container( + decoration: BoxDecoration(color: Colors.white), + child: QrImage( + data: qr, + size: 200.0, + gapless: true, + ), + ), + SizedBox(height: 10), + SizedBox( + width: 200, + child: LinearProgressIndicator( + value: timer.toDouble() / timeoutValue.toDouble(), + semanticsLabel: 'Timeout Timer for HiveAuth QR', + ), + ), + ], + ), + didTapKeychainButton + ? Column( + children: [ + const SizedBox(height: 10), + const Text( + 'Authorize this request with "Keychain for Hive" app.'), + const SizedBox(height: 20), + ElevatedButton( + onPressed: () { + var url = Uri.parse(qr); + launchUrl(url); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black), + child: Image.asset('assets/hive-keychain-image.png', + width: 220), + ), + const SizedBox(height: 20), + SizedBox(height: 10), + SizedBox( + width: 200, + child: LinearProgressIndicator( + value: timer.toDouble() / timeoutValue.toDouble(), + semanticsLabel: 'Timeout Timer for HiveAuth QR', + ), + ), + ], + ) + : Container() ], ), ); } Widget _loginForm(HiveUserData appData) { - return loadingQR + return loadingQR || isLoading ? const Center(child: CircularProgressIndicator()) : qrCode == null ? Container( @@ -195,14 +281,74 @@ class _HiveAuthLoginScreenState extends State child: Column( children: [ _hiveUserName(), - SizedBox(height: 20), - _hasButton(appData) + const SizedBox(height: 10), + _hasButton(appData), + const SizedBox(height: 10), + const Text('- OR -'), + const SizedBox(height: 10), + _hivePostingKey(), + const SizedBox(height: 10), + ElevatedButton( + onPressed: () { + onLoginTapped(appData); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black), + child: const Text('Login with Posting Key'), + ), ], ), ) : _showQRCodeAndKeychainButton(qrCode!); } + void onLoginTapped(HiveUserData appData) async { + setState(() { + isLoading = true; + }); + try { + var publicKey = await Communicator().getPublicKey(username, appData.rpc); + var resultingKey = CryptoManager().privToPub(postingKey); + if (resultingKey == publicKey) { + // it is valid key + debugPrint("Successful login"); + String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + await storage.write(key: 'username', value: username); + await storage.write(key: 'postingKey', value: postingKey); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); + await storage.delete(key: 'cookie'); + server.updateHiveUserData( + HiveUserData( + username: username, + postingKey: postingKey, + keychainData: null, + cookie: null, + resolution: resolution, + rpc: rpc, + ), + ); + Navigator.of(context).pop(); + setState(() { + isLoading = false; + }); + } else { + // it is NO valid key + showError('Not valid key.'); + setState(() { + isLoading = false; + }); + } + } catch (e) { + setState(() { + isLoading = false; + }); + showError('Error occurred - ${e.toString()}'); + } + } + @override void dispose() { super.dispose(); @@ -262,7 +408,7 @@ class _HiveAuthLoginScreenState extends State var data = Provider.of(context); return Scaffold( appBar: AppBar( - title: const Text('Login with Hive Auth'), + title: const Text('Sign in with your account'), ), body: _loginForm(data), ); diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 208d7434..661e6b9a 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -149,14 +149,14 @@ class _LoginScreenState extends State { }, icon: Icon(Icons.help), ), - // IconButton( - // onPressed: () { - // var screen = HiveAuthLoginScreen(appData: data); - // var route = MaterialPageRoute(builder: (c) => screen); - // Navigator.of(context).push(route); - // }, - // icon: Image.asset('assets/hiveauth_icon.png'), - // ) + IconButton( + onPressed: () { + var screen = HiveAuthLoginScreen(appData: data); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + icon: Image.asset('assets/hiveauth_icon.png'), + ) ], ), body: _loginForm(data), diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index 49a19873..847289ba 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -309,9 +309,9 @@ class _NewVideoUploadScreenState extends State { }, ); AlertDialog alert = AlertDialog( - title: Text("🎉 Congratulations 🎉"), + title: Text("🎉 Upload Complete 🎉"), content: Text( - "✅ Your Video is uploaded.\n✅It is also moved to encoding queue.\n- Don't forget to check your video status from My Account section."), + "✅ Your Video is in process.\n✅Video has be added to the encoding queue.\n- Don't forget to check your video status from My Account section."), actions: [ okButton, ], @@ -396,22 +396,22 @@ class _NewVideoUploadScreenState extends State { ), body: ListView( children: [ - ListTile( - title: const Text('Launching Video Picker'), - trailing: didShowFilePicker - ? const Icon(Icons.check, color: Colors.lightGreen) - : const Icon(Icons.pending), - subtitle: didShowFilePicker ? Text(timeShowFilePicker) : null, - ), - ListTile( - title: const Text('Getting/Compressing the Video'), - trailing: !didPickFile - ? !didStartPickFile - ? const Icon(Icons.pending) - : const CircularProgressIndicator() - : const Icon(Icons.check, color: Colors.lightGreen), - subtitle: didPickFile ? Text(timePickFile) : null, - ), + // ListTile( + // title: const Text('Launching Video Picker'), + // trailing: didShowFilePicker + // ? const Icon(Icons.check, color: Colors.lightGreen) + // : const Icon(Icons.pending), + // subtitle: didShowFilePicker ? Text(timeShowFilePicker) : null, + // ), + // ListTile( + // title: const Text('Getting/Compressing the Video'), + // trailing: !didPickFile + // ? !didStartPickFile + // ? const Icon(Icons.pending) + // : const CircularProgressIndicator() + // : const Icon(Icons.check, color: Colors.lightGreen), + // subtitle: didPickFile ? Text(timePickFile) : null, + // ), ListTile( title: Text( 'Uploading video (${didUpload ? 100.0 : (progress * 100).toStringAsFixed(2)}%)'), From 450f91c2a3dc2e2f7beef6f1a6199c0fab4a9c87 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sat, 11 Feb 2023 17:36:11 +0530 Subject: [PATCH 164/466] New video upload process. --- .flutter-plugins-dependencies | 2 +- .../screens/drawer_screen/drawer_screen.dart | 8 +-- lib/src/screens/home_screen/home_screen.dart | 16 ++--- lib/src/screens/login/ha_login_screen.dart | 28 +++++---- lib/src/screens/login/login_screen.dart | 5 +- .../screens/my_account/my_account_screen.dart | 40 +++++++++--- .../update_video/video_details_info.dart | 10 +++ .../update_video/video_primary_info.dart | 3 + lib/src/screens/stories/stories_feed.dart | 2 +- .../upload/new_video_upload_screen.dart | 63 +++++++++---------- lib/src/utils/communicator.dart | 8 ++- 11 files changed, 117 insertions(+), 68 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index a14fe528..530c4732 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-02-10 15:47:04.822833","version":"3.7.0-1.5.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-02-11 15:57:14.788367","version":"3.7.0-1.5.pre"} \ No newline at end of file diff --git a/lib/src/screens/drawer_screen/drawer_screen.dart b/lib/src/screens/drawer_screen/drawer_screen.dart index e2174a0d..25a63cfe 100644 --- a/lib/src/screens/drawer_screen/drawer_screen.dart +++ b/lib/src/screens/drawer_screen/drawer_screen.dart @@ -3,7 +3,7 @@ import 'package:acela/src/screens/about/about_home_screen.dart'; import 'package:acela/src/screens/communities_screen/communities_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen.dart'; import 'package:acela/src/screens/leaderboard_screen/leaderboard_screen.dart'; -import 'package:acela/src/screens/login/login_screen.dart'; +import 'package:acela/src/screens/login/ha_login_screen.dart'; import 'package:acela/src/screens/my_account/my_account_screen.dart'; import 'package:acela/src/screens/settings/settings_screen.dart'; import 'package:acela/src/screens/stories/stories_screen.dart'; @@ -137,7 +137,7 @@ class DrawerScreen extends StatelessWidget { ); } - Widget _login(BuildContext context) { + Widget _login(BuildContext context, HiveUserData data) { return ListTile( leading: const Icon(Icons.login), title: const Text("Log in"), @@ -146,7 +146,7 @@ class DrawerScreen extends StatelessWidget { // Navigator.of(context) // .push(MaterialPageRoute(builder: (c) => const NewLoginScreen())); Navigator.of(context) - .push(MaterialPageRoute(builder: (c) => const LoginScreen())); + .push(MaterialPageRoute(builder: (c) => HiveAuthLoginScreen(appData: data))); }, ); } @@ -227,7 +227,7 @@ class DrawerScreen extends StatelessWidget { _divider(), _settings(context), _divider(), - user.username == null ? _login(context) : _myAccount(context), + user.username == null ? _login(context, user) : _myAccount(context), _divider(), _importantLinks(context), _divider(), diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index e40966a2..8e28958e 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -147,7 +147,7 @@ class _HomeScreenState extends State { ); } - void showBottomSheetForVideoOptions(bool isReel) { + void showBottomSheetForVideoOptions(bool isReel, HiveUserData data) { showAdaptiveActionSheet( context: context, title: const Text('How do you want to upload?'), @@ -160,6 +160,7 @@ class _HomeScreenState extends State { var screen = NewVideoUploadScreen( camera: true, isReel: isReel, + data: data, ); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).pop(); @@ -173,6 +174,7 @@ class _HomeScreenState extends State { var screen = NewVideoUploadScreen( camera: false, isReel: isReel, + data: data, ); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).pop(); @@ -185,7 +187,7 @@ class _HomeScreenState extends State { ); } - void showBottomSheetForRecordingTypes() { + void showBottomSheetForRecordingTypes(HiveUserData data) { showAdaptiveActionSheet( context: context, title: const Text('What do you want to upload?'), @@ -196,7 +198,7 @@ class _HomeScreenState extends State { leading: const Icon(Icons.camera_outlined), onPressed: (c) { Navigator.of(context).pop(); - showBottomSheetForVideoOptions(true); + showBottomSheetForVideoOptions(true, data); }, ), BottomSheetAction( @@ -204,17 +206,17 @@ class _HomeScreenState extends State { leading: const Icon(Icons.video_collection), onPressed: (c) { Navigator.of(context).pop(); - showBottomSheetForVideoOptions(false); + showBottomSheetForVideoOptions(false, data); }), ], cancelAction: CancelAction(title: const Text('Cancel')), ); } - Widget _fabNewUpload() { + Widget _fabNewUpload(HiveUserData data) { return FloatingActionButton.extended( onPressed: () { - showBottomSheetForRecordingTypes(); + showBottomSheetForRecordingTypes(data); }, label: const Text('Upload Video'), icon: const Icon(Icons.upload), @@ -250,7 +252,7 @@ class _HomeScreenState extends State { ), body: _screen(appData), drawer: widget.showDrawer ? const DrawerScreen() : null, - floatingActionButton: appData.username == null ? null : _fabNewUpload(), + floatingActionButton: appData.username == null ? null : _fabNewUpload(appData), ); } } diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index d178c10e..d9ebbf4a 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -33,7 +33,6 @@ class _HiveAuthLoginScreenState extends State var usernameController = TextEditingController(); late WebSocketChannel socket; String authKey = ''; - String username = ''; String? qrCode; var loadingQR = false; var timer = 0; @@ -139,7 +138,10 @@ class _HiveAuthLoginScreenState extends State } void _hasButtonTapped(bool keychainTapped) async { - if (usernameController.text.isEmpty) return; + if (usernameController.text.isEmpty) { + showError('Please enter hive username'); + return; + } setState(() { loadingQR = true; }); @@ -161,7 +163,6 @@ class _HiveAuthLoginScreenState extends State setState(() { didTapKeychainButton = keychainTapped; authKey = key; - username = usernameController.text; }); } } @@ -303,18 +304,21 @@ class _HiveAuthLoginScreenState extends State } void onLoginTapped(HiveUserData appData) async { + if (usernameController.text.isEmpty) { + showError('Please enter hive username'); + return; + } setState(() { isLoading = true; }); try { - var publicKey = await Communicator().getPublicKey(username, appData.rpc); + var publicKey = await Communicator().getPublicKey(usernameController.text, appData.rpc); var resultingKey = CryptoManager().privToPub(postingKey); if (resultingKey == publicKey) { - // it is valid key debugPrint("Successful login"); String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - await storage.write(key: 'username', value: username); + await storage.write(key: 'username', value: usernameController.text); await storage.write(key: 'postingKey', value: postingKey); await storage.delete(key: 'hasId'); await storage.delete(key: 'hasExpiry'); @@ -322,7 +326,7 @@ class _HiveAuthLoginScreenState extends State await storage.delete(key: 'cookie'); server.updateHiveUserData( HiveUserData( - username: username, + username: usernameController.text, postingKey: postingKey, keychainData: null, cookie: null, @@ -331,6 +335,7 @@ class _HiveAuthLoginScreenState extends State ), ); Navigator.of(context).pop(); + showMessage('You have successfully logged in as - ${usernameController.text}'); setState(() { isLoading = false; }); @@ -358,7 +363,7 @@ class _HiveAuthLoginScreenState extends State void decryptData(HiveUserData data, String encryptedData) async { final String response = await platform.invokeMethod('getDecryptedHASToken', { - 'username': username, + 'username': usernameController.text, 'authKey': authKey, 'data': encryptedData, }); @@ -372,7 +377,7 @@ class _HiveAuthLoginScreenState extends State 'Did not find token & expiry details from HiveAuth. Please go back & try again.'); } else { const storage = FlutterSecureStorage(); - await storage.write(key: 'username', value: username); + await storage.write(key: 'username', value: usernameController.text); await storage.delete(key: 'postingKey'); await storage.delete(key: 'cookie'); await storage.write(key: 'hasId', value: tokenData[0]); @@ -380,7 +385,7 @@ class _HiveAuthLoginScreenState extends State await storage.write(key: 'hasAuthKey', value: authKey); server.updateHiveUserData( HiveUserData( - username: username, + username: usernameController.text, postingKey: null, keychainData: HiveKeychainData( hasAuthKey: authKey, @@ -393,8 +398,7 @@ class _HiveAuthLoginScreenState extends State ), ); showMessage( - 'You have successfully logged in with Hive Auth with user - $username'); - Navigator.of(context).pop(); + 'You have successfully logged in with Hive Auth with user - ${usernameController.text}'); Navigator.of(context).pop(); } } else { diff --git a/lib/src/screens/login/login_screen.dart b/lib/src/screens/login/login_screen.dart index 661e6b9a..e2965971 100644 --- a/lib/src/screens/login/login_screen.dart +++ b/lib/src/screens/login/login_screen.dart @@ -6,7 +6,7 @@ import 'package:acela/src/utils/crypto_manager.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:provider/provider.dart'; - +/* class LoginScreen extends StatefulWidget { const LoginScreen({Key? key}) : super(key: key); @@ -163,3 +163,6 @@ class _LoginScreenState extends State { ); } } + + + */ \ No newline at end of file diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 0b8b3923..06792632 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -42,10 +42,31 @@ class _MyAccountScreenState extends State { ), bottom: const TabBar( tabs: [ - Tab(icon: Icon(Icons.hourglass_top)), - Tab(icon: Icon(Icons.rocket_launch)), - Tab(icon: Icon(Icons.check)), - Tab(icon: Icon(Icons.cancel_rounded)), + Tab( + child: Text( + 'Encoding', + style: TextStyle(color: Colors.yellowAccent), + ), + ), + Tab( + child: Text( + 'Ready', + style: TextStyle(color: Colors.green), + ), + ), + Tab( + child: Text( + 'Done', + style: TextStyle(color: Colors.blueAccent), + ), + ), + Tab( + child: Text( + 'Failed', + style: TextStyle(color: Colors.red), + ), + ), + //(icon: Icon(Icons.cancel_rounded)), ], ), actions: [ @@ -69,7 +90,10 @@ class _MyAccountScreenState extends State { : item.status == 'publish_manual' ? IconButton( onPressed: () { - var screen = VideoPrimaryInfo(item: item); + var screen = VideoPrimaryInfo( + item: item, + justForEditing: false, + ); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); }, @@ -121,7 +145,7 @@ class _MyAccountScreenState extends State { item.status != 'encoding_failed') { _showBottomSheet(item); } else if (item.status == 'publish_manual') { - var screen = VideoPrimaryInfo(item: item); + var screen = VideoPrimaryInfo(item: item, justForEditing: false); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); } @@ -151,7 +175,9 @@ class _MyAccountScreenState extends State { items.where((item) => item.status == 'encoding_failed').toList(); var process = items .where((item) => - item.status != 'published' && item.status != 'publish_manual') + item.status != 'published' && + item.status != 'publish_manual' && + item.status != 'encoding_failed') .toList(); return TabBarView( children: [ diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index 1a8495a9..14685bdd 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -23,10 +23,12 @@ class VideoDetailsInfo extends StatefulWidget { required this.item, required this.title, required this.subtitle, + required this.justForEditing, }) : super(key: key); final VideoDetails item; final String title; final String subtitle; + final bool justForEditing; @override State createState() => _VideoDetailsInfoState(); @@ -192,6 +194,14 @@ class _VideoDetailsInfoState extends State { tags: tags, thumbnail: thumbIpfs.isEmpty ? null : thumbIpfs, ); + if (widget.justForEditing) { + setState(() { + showMessage('Video details are saved.'); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + return; + }); + } await Future.delayed(const Duration(seconds: 1), () {}); const platform = MethodChannel('com.example.acela/auth'); var title = base64.encode(utf8.encode(widget.title)); diff --git a/lib/src/screens/my_account/update_video/video_primary_info.dart b/lib/src/screens/my_account/update_video/video_primary_info.dart index fdfd5859..2a42ecf0 100644 --- a/lib/src/screens/my_account/update_video/video_primary_info.dart +++ b/lib/src/screens/my_account/update_video/video_primary_info.dart @@ -6,8 +6,10 @@ class VideoPrimaryInfo extends StatefulWidget { const VideoPrimaryInfo({ Key? key, required this.item, + required this.justForEditing, }) : super(key: key); final VideoDetails item; + final bool justForEditing; @override State createState() => _VideoPrimaryInfoState(); @@ -82,6 +84,7 @@ class _VideoPrimaryInfoState extends State { item: widget.item, title: titleController.text, subtitle: descriptionController.text, + justForEditing: widget.justForEditing, ); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); diff --git a/lib/src/screens/stories/stories_feed.dart b/lib/src/screens/stories/stories_feed.dart index c2fe0df7..20eb89f0 100644 --- a/lib/src/screens/stories/stories_feed.dart +++ b/lib/src/screens/stories/stories_feed.dart @@ -59,7 +59,7 @@ class _StoriesFeedScreenState extends State { .toList(); var permlinks = Set(); items.retainWhere((x) => permlinks.add(x.permlink)); - if (items.length < 10) { + if (items.length < 15) { loadData(length + list.length); } }); diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index 847289ba..ccbd36d5 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -3,6 +3,9 @@ import 'dart:developer'; import 'dart:io'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/models/video_details_model/video_details.dart'; +import 'package:acela/src/models/video_upload/video_upload_prepare_response.dart'; +import 'package:acela/src/screens/my_account/update_video/video_primary_info.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; import 'package:ffmpeg_kit_flutter/media_information_session.dart'; @@ -18,7 +21,9 @@ import 'package:video_thumbnail/video_thumbnail.dart'; class UploadedItem { String fileName; String filePath; + UploadedItem({required this.fileName, required this.filePath}); + toJSONEncodable() { Map m = new Map(); m['fileName'] = fileName; @@ -42,9 +47,11 @@ class NewVideoUploadScreen extends StatefulWidget { Key? key, required this.camera, required this.isReel, + required this.data, }) : super(key: key); final bool camera; final bool isReel; + final HiveUserData data; @override State createState() => _NewVideoUploadScreenState(); @@ -53,6 +60,7 @@ class NewVideoUploadScreen extends StatefulWidget { class _NewVideoUploadScreenState extends State { var didShowFilePicker = false; var didPickFile = false; + // var didCompress = false; var didUpload = false; var didTakeDefaultThumbnail = false; @@ -61,6 +69,7 @@ class _NewVideoUploadScreenState extends State { var timeShowFilePicker = '0.5 seconds'; var timePickFile = ''; + // var timeCompress = ''; var timeUpload = ''; var timeTakeDefaultThumbnail = ''; @@ -68,6 +77,7 @@ class _NewVideoUploadScreenState extends State { var timeMoveToQueue = ''; var didStartPickFile = false; + // var didStartCompress = false; var didStartUpload = false; var didStartTakeDefaultThumbnail = false; @@ -161,8 +171,6 @@ class _NewVideoUploadScreenState extends State { var originalFileName = file.name; var fileToSave = File(file.path); log(originalFileName); - // log("bytes - ${videoFile.bytes ?? 0}"); - // log("size - ${file.size}"); log("path - ${file.path}"); var alreadyUploaded = list.items.contains((e) { return e.fileName == originalFileName || e.filePath == file!.path; @@ -171,32 +179,7 @@ class _NewVideoUploadScreenState extends State { throw 'This video is already uploaded by you'; } var size = await file.length(); - // var size = file.size; - // ---- Step 1. Select Video - - /* - var status = await Permission.storage.status; - if (!status.isGranted) { - await Permission.storage.request(); - } - - List? storage = await getExternalStorageDirectories(); - if (storage == null) { - throw 'Storage null'; - } - var externalDirPath = storage.first.path; - - var pathOfDir = file.path.replaceAll(file.name, ""); - var resultOfFfmpeg = await FFmpegKit.execute( - "-i ${file.path} -codec: copy -bsf:v h264_mp4toannexb -start_number 0 -hls_time 10 -hls_list_size 0 -f hls $externalDirPath/index.m3u8"); - log('Result is ${resultOfFfmpeg.toString()}'); - var code = await resultOfFfmpeg.getReturnCode(); - final output = await resultOfFfmpeg.getOutput(); - log('code is ${(code?.isValueSuccess() ?? false) ? 'Success' : 'Failure'}'); - log('output is ${output.toString()}'); - throw 'Throwing error now'; -*/ if (widget.camera) { await ImagesPicker.saveVideoToAlbum(fileToSave); } @@ -280,13 +263,17 @@ class _NewVideoUploadScreenState extends State { ); _addItem(originalFileName, file.path); log(videoUploadInfo.status); + var videosInfo = await Communicator().loadVideos(widget.data); + var item = videosInfo.firstWhere((element) => + element.permlink == videoUploadInfo.permlink && + element.owner == videoUploadInfo.owner); var dateEndMoveToQueue = DateTime.now(); diff = dateEndMoveToQueue.difference(dateStartMoveToQueue); setState(() { timeMoveToQueue = '${diff.inSeconds} seconds'; didMoveToQueue = true; showMessage('Video is uploaded & moved to encoding queue'); - showMyDialog(); + showMyDialog(item); }); // Step 6. Move Video to Queue } else { @@ -300,20 +287,30 @@ class _NewVideoUploadScreenState extends State { } } - void showMyDialog() { - Widget okButton = TextButton( - child: Text("Okay"), + void showMyDialog(VideoDetails item) { + Widget laterButton = TextButton( + child: Text("Later"), onPressed: () { Navigator.of(context).pop(); Navigator.of(context).pop(); }, ); + Widget nowButton = TextButton( + onPressed: () async { + Navigator.of(context).pop(); + Navigator.of(context).pop(); + var screen = VideoPrimaryInfo(item: item, justForEditing: true); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + child: const Text('Edit')); AlertDialog alert = AlertDialog( title: Text("🎉 Upload Complete 🎉"), content: Text( - "✅ Your Video is in process.\n✅Video has be added to the encoding queue.\n- Don't forget to check your video status from My Account section."), + "✅ Your Video is in-process\n\n✅ Video has be added to encoding queue\n\n👀 Check status from My Account\n\n📝 Would you like to Edit your video now?"), actions: [ - okButton, + laterButton, + nowButton, ], ); showDialog(context: context, builder: (c) => alert); diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index aeb6327e..b1653cf8 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -34,8 +34,12 @@ class Communicator { // static const fsServer = "http://localhost:1080/files"; // iOS Devices - Local Server Testing - static const tsServer = "http://192.168.29.239:13050"; - static const fsServer = "http://192.168.29.239:1080/files"; + // static const tsServer = "http://192.168.29.239:13050"; + // static const fsServer = "http://192.168.29.239:1080/files"; + + // iOS Devices - Local server testing different router + static const tsServer = "http://192.168.1.2:13050"; + static const fsServer = "http://192.168.1.2:1080/files"; // static const hiveApiUrl = 'api.hive.blog'; static const threeSpeakCDN = 'https://ipfs-3speak.b-cdn.net'; From cab19c486abc53febbf7c54637f7b564cf704668 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 17 Feb 2023 16:54:16 +0530 Subject: [PATCH 165/466] UI Bug fixes. --- .flutter-plugins-dependencies | 2 +- lib/src/screens/login/ha_login_screen.dart | 4 +- .../screens/my_account/my_account_screen.dart | 134 +++++++++++------- lib/src/utils/communicator.dart | 8 +- 4 files changed, 88 insertions(+), 60 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 530c4732..3a35a35c 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-02-11 15:57:14.788367","version":"3.7.0-1.5.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-02-15 08:52:07.715697","version":"3.7.0-1.5.pre"} \ No newline at end of file diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index d9ebbf4a..156e0b17 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -195,8 +195,8 @@ class _HiveAuthLoginScreenState extends State return TextField( decoration: InputDecoration( icon: const Icon(Icons.key), - label: const Text('Hive Posting Key'), - hintText: 'Copy & paste posting key here', + label: const Text('Hive Private Posting Key'), + hintText: 'Copy & paste Private posting key here', ), obscureText: true, onChanged: (value) { diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 06792632..17efe4e1 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -19,8 +19,28 @@ class MyAccountScreen extends StatefulWidget { State createState() => _MyAccountScreenState(); } -class _MyAccountScreenState extends State { +class _MyAccountScreenState extends State + with SingleTickerProviderStateMixin { Future>? loadVideos; + late TabController _tabController; + var currentIndex = 0; + + @override + void initState() { + super.initState(); + _tabController = TabController(length: 4, vsync: this); + _tabController.addListener(() { + setState(() { + currentIndex = _tabController.index; + }); + }); + } + + @override + void dispose() { + super.dispose(); + _tabController.dispose(); + } void showError(String string) { var snackBar = SnackBar(content: Text('Error: $string')); @@ -28,43 +48,50 @@ class _MyAccountScreenState extends State { } AppBar _appBar(String username) { + var text = currentIndex == 0 + ? 'Videos - in Encoding Process' + : currentIndex == 1 ? 'Videos - Ready to post' : currentIndex == + 2 ? 'Videos - Already posted' : 'Videos - failed to encode'; return AppBar( - title: Row( - children: [ - CustomCircleAvatar( - height: 36, - width: 36, - url: 'https://images.hive.blog/u/$username/avatar', - ), - const SizedBox(width: 5), - Text(username), - ], + title: ListTile( + leading: CustomCircleAvatar( + height: 36, + width: 36, + url: 'https://images.hive.blog/u/$username/avatar', + ), + title: Text(username), + subtitle: Text(text), ), - bottom: const TabBar( + bottom: TabBar( + controller: _tabController, tabs: [ Tab( - child: Text( - 'Encoding', - style: TextStyle(color: Colors.yellowAccent), - ), + icon: Icon(Icons.hourglass_top, color: Colors.yellowAccent), + // child: Text( + // 'Encoding', + // style: TextStyle(color: Colors.yellowAccent), + // ), ), Tab( - child: Text( - 'Ready', - style: TextStyle(color: Colors.green), - ), + icon: Icon(Icons.rocket_launch, color: Colors.green), + // child: Text( + // 'Ready', + // style: TextStyle(color: Colors.green), + // ), ), Tab( - child: Text( - 'Done', - style: TextStyle(color: Colors.blueAccent), - ), + icon: Icon(Icons.check, color: Colors.blueAccent), + // child: Text( + // 'Done', + // style: TextStyle(color: Colors.blueAccent), + // ), ), Tab( - child: Text( - 'Failed', - style: TextStyle(color: Colors.red), - ), + icon: Icon(Icons.cancel_rounded, color: Colors.red), + // child: Text( + // 'Failed', + // style: TextStyle(color: Colors.red), + // ), ), //(icon: Icon(Icons.cancel_rounded)), ], @@ -84,28 +111,28 @@ class _MyAccountScreenState extends State { Widget _trailingActionOnVideoListItem(VideoDetails item, HiveUserData user) { return item.status == 'published' - ? const Icon(Icons.check, color: Colors.green) + ? const Icon(Icons.check, color: Colors.blueAccent) : item.status == "encoding_failed" - ? const Icon(Icons.cancel_outlined, color: Colors.red) - : item.status == 'publish_manual' - ? IconButton( - onPressed: () { - var screen = VideoPrimaryInfo( - item: item, - justForEditing: false, - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - icon: const Icon( - Icons.rocket_launch, - color: Colors.green, - ), - ) - : const Icon( - Icons.hourglass_top, - color: Colors.blue, - ); + ? const Icon(Icons.cancel_outlined, color: Colors.red) + : item.status == 'publish_manual' + ? IconButton( + onPressed: () { + var screen = VideoPrimaryInfo( + item: item, + justForEditing: false, + ); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + icon: const Icon( + Icons.rocket_launch, + color: Colors.green, + ), + ) + : const Icon( + Icons.hourglass_top, + color: Colors.yellowAccent, + ); } void _showBottomSheet(VideoDetails item) { @@ -172,14 +199,15 @@ class _MyAccountScreenState extends State { var published = items.where((item) => item.status == 'published').toList(); var ready = items.where((item) => item.status == 'publish_manual').toList(); var failed = - items.where((item) => item.status == 'encoding_failed').toList(); + items.where((item) => item.status == 'encoding_failed').toList(); var process = items .where((item) => - item.status != 'published' && - item.status != 'publish_manual' && - item.status != 'encoding_failed') + item.status != 'published' && + item.status != 'publish_manual' && + item.status != 'encoding_failed') .toList(); return TabBarView( + controller: _tabController, children: [ SafeArea( child: _listViewForItems(process, user), diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index b1653cf8..d55585d5 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -34,12 +34,12 @@ class Communicator { // static const fsServer = "http://localhost:1080/files"; // iOS Devices - Local Server Testing - // static const tsServer = "http://192.168.29.239:13050"; - // static const fsServer = "http://192.168.29.239:1080/files"; + static const tsServer = "http://192.168.29.53:13050"; + static const fsServer = "http://192.168.29.53:1080/files"; // iOS Devices - Local server testing different router - static const tsServer = "http://192.168.1.2:13050"; - static const fsServer = "http://192.168.1.2:1080/files"; + // static const tsServer = "http://192.168.1.2:13050"; + // static const fsServer = "http://192.168.1.2:1080/files"; // static const hiveApiUrl = 'api.hive.blog'; static const threeSpeakCDN = 'https://ipfs-3speak.b-cdn.net'; From 6050fcd569f3ffd80615c5120dc321ea9abef844 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 22 Feb 2023 12:30:30 +0530 Subject: [PATCH 166/466] Bug fixes --- .flutter-plugins | 14 ++-- .flutter-plugins-dependencies | 2 +- .idea/libraries/Flutter_Plugins.xml | 12 +-- ios/Podfile.lock | 2 +- lib/src/screens/home_screen/home_screen.dart | 51 +++++++++++- .../upload/new_video_upload_screen.dart | 6 +- lib/src/utils/communicator.dart | 8 +- pubspec.lock | 82 +++++++++---------- 8 files changed, 113 insertions(+), 64 deletions(-) diff --git a/.flutter-plugins b/.flutter-plugins index a2e3eadf..cdb05a59 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -9,19 +9,19 @@ ffmpeg_kit_flutter=/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5 file_picker=/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/ flutter_plugin_android_lifecycle=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/ flutter_secure_storage=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/ -flutter_secure_storage_linux=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/ +flutter_secure_storage_linux=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.3/ flutter_secure_storage_macos=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/ flutter_secure_storage_web=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/ flutter_secure_storage_windows=/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/ -image_picker=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker-0.8.6+1/ -image_picker_android=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/ +image_picker=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker-0.8.6+2/ +image_picker_android=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+6/ image_picker_for_web=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/ -image_picker_ios=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/ +image_picker_ios=/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+8/ images_picker=/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/ path_provider=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider-2.0.12/ path_provider_android=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/ path_provider_foundation=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/ -path_provider_linux=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/ +path_provider_linux=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.8/ path_provider_windows=/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/ permission_handler=/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler-10.2.0/ permission_handler_android=/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/ @@ -32,9 +32,9 @@ share_plus_linux=/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/ share_plus_macos=/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/ share_plus_web=/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/ share_plus_windows=/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/ -url_launcher=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher-6.1.8/ +url_launcher=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher-6.1.9/ url_launcher_android=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/ -url_launcher_ios=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/ +url_launcher_ios=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.1.0/ url_launcher_linux=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/ url_launcher_macos=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/ url_launcher_web=/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 3a35a35c..52443aea 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+6/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.0.18/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-02-15 08:52:07.715697","version":"3.7.0-1.5.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+8/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.1.0/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+6/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.8/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-02-22 11:11:13.901203","version":"3.7.0-1.5.pre"} \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 770ef48d..8075d22d 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -22,7 +22,6 @@ - @@ -35,18 +34,19 @@ - - - - - + + + + + + diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 380851da..201c48da 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -205,7 +205,7 @@ SPEC CHECKSUMS: SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 - url_launcher_ios: ae1517e5e344f5544fb090b079e11f399dfbe4d2 + url_launcher_ios: fb12c43172927bb5cf75aeebd073f883801f1993 video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1 diff --git a/lib/src/screens/home_screen/home_screen.dart b/lib/src/screens/home_screen/home_screen.dart index 8e28958e..d5090d0f 100644 --- a/lib/src/screens/home_screen/home_screen.dart +++ b/lib/src/screens/home_screen/home_screen.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; @@ -14,6 +15,7 @@ import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/retry.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:http/http.dart' show get; import 'package:provider/provider.dart'; @@ -213,10 +215,57 @@ class _HomeScreenState extends State { ); } + void logout(HiveUserData data) async { + const storage = FlutterSecureStorage(); + await storage.delete(key: 'username'); + await storage.delete(key: 'postingKey'); + await storage.delete(key: 'cookie'); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); + String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + server.updateHiveUserData( + HiveUserData( + username: null, + postingKey: null, + keychainData: null, + cookie: null, + resolution: resolution, + rpc: rpc, + ), + ); + } + Widget _fabNewUpload(HiveUserData data) { return FloatingActionButton.extended( onPressed: () { - showBottomSheetForRecordingTypes(data); + if (data.username != null && data.postingKey != null) { + showBottomSheetForRecordingTypes(data); + } else if (data.keychainData != null) { + var expiry = data.keychainData!.hasExpiry; + log('Expiry is $expiry'); + try { + var longValue = int.tryParse(expiry) ?? 0; + var expiryDate = DateTime.fromMillisecondsSinceEpoch(longValue); + var nowDate = DateTime.now(); + log('Expiry Date is $expiryDate, now date is $nowDate'); + var compareResult = nowDate.compareTo(expiryDate); + log('compare result - $compareResult'); + if (compareResult == -1) { + showBottomSheetForRecordingTypes(data); + } else { + showError('Invalid Session. Please login again.'); + logout(data); + } + } catch (e) { + showError('Invalid Session. Please login again.'); + logout(data); + } + } else { + showError('Invalid Session. Please login again.'); + logout(data); + } }, label: const Text('Upload Video'), icon: const Icon(Icons.upload), diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index ccbd36d5..a31ea251 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -289,7 +289,7 @@ class _NewVideoUploadScreenState extends State { void showMyDialog(VideoDetails item) { Widget laterButton = TextButton( - child: Text("Later"), + child: Text("Skip"), onPressed: () { Navigator.of(context).pop(); Navigator.of(context).pop(); @@ -303,11 +303,11 @@ class _NewVideoUploadScreenState extends State { var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); }, - child: const Text('Edit')); + child: const Text('Next')); AlertDialog alert = AlertDialog( title: Text("🎉 Upload Complete 🎉"), content: Text( - "✅ Your Video is in-process\n\n✅ Video has be added to encoding queue\n\n👀 Check status from My Account\n\n📝 Would you like to Edit your video now?"), + "✅ Your Video is in-process\n\n✅ Video has be added to encoding queue\n\n👀 Check status from My Account\n\n📝 Let's edit video details now."), actions: [ laterButton, nowButton, diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index d55585d5..4a417b68 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -22,8 +22,8 @@ import 'package:http/http.dart' as http; class Communicator { // Production - // static const tsServer = "https://studio.3speak.tv"; - // static const fsServer = "https://uploads.3speak.tv/files"; + static const tsServer = "https://studio.3speak.tv"; + static const fsServer = "https://uploads.3speak.tv/files"; // Android // static const fsServer = "http://10.0.2.2:1080/files"; @@ -34,8 +34,8 @@ class Communicator { // static const fsServer = "http://localhost:1080/files"; // iOS Devices - Local Server Testing - static const tsServer = "http://192.168.29.53:13050"; - static const fsServer = "http://192.168.29.53:1080/files"; + // static const tsServer = "http://192.168.29.53:13050"; + // static const fsServer = "http://192.168.29.53:1080/files"; // iOS Devices - Local server testing different router // static const tsServer = "http://192.168.1.2:13050"; diff --git a/pubspec.lock b/pubspec.lock index f2a66c55..02d8eca7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0c80aeab9bc807ab10022cd3b2f4cf2ecdf231949dc1ddd9442406a003f19201" + sha256: "569ddca58d535e601dd1584afa117710abc999d036c0cd2c51777fb257df78e8" url: "https://pub.dev" source: hosted - version: "52.0.0" + version: "53.0.0" adaptive_action_sheet: dependency: "direct main" description: @@ -21,18 +21,18 @@ packages: dependency: transitive description: name: analyzer - sha256: cd8ee83568a77f3ae6b913a36093a1c9b1264e7cb7f834d9ddd2311dade9c1f4 + sha256: "10927c4b7c7c88b1adbca278c3d5531db92e2f4b4abf04e2919a800af965f3f5" url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "5.5.0" args: dependency: transitive description: name: args - sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611" + sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" asn1lib: dependency: transitive description: @@ -126,10 +126,10 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "7c35a3a7868626257d8aee47b51c26b9dba11eaddf3431117ed2744951416aab" + sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.2.0" build_runner: dependency: "direct dev" description: @@ -230,10 +230,10 @@ packages: dependency: transitive description: name: cross_file - sha256: f71079978789bc2fe78d79227f1f8cfe195b31bbd8db2399b0d15a4b96fb843b + sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" url: "https://pub.dev" source: hosted - version: "0.3.3+2" + version: "0.3.3+4" crypto: dependency: "direct main" description: @@ -419,10 +419,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: "981442432b632237ffc1cf8092b4173b9e9f2278b5740637287c3069b51c8f09" + sha256: "7b25c10de1fea883f3c4f9b8389506b54053cd00807beab69fd65c8653a2711f" url: "https://pub.dev" source: hosted - version: "0.6.13" + version: "0.6.14" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -443,10 +443,10 @@ packages: dependency: transitive description: name: flutter_secure_storage_linux - sha256: "736436adaf91552433823f51ce22e098c2f0551db06b6596f58597a25b8ea797" + sha256: "0912ae29a572230ad52d8a4697e5518d7f0f429052fd51df7e5a7952c7efe2a3" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.3" flutter_secure_storage_macos: dependency: transitive description: @@ -501,10 +501,10 @@ packages: dependency: "direct main" description: name: font_awesome_flutter - sha256: "875dbb9ec1ad30d68102019ceb682760d06c72747c1c5b7885781b95f88569cc" + sha256: "959ef4add147753f990b4a7c6cccb746d5792dbdc81b1cde99e62e7edb31b206" url: "https://pub.dev" source: hosted - version: "10.3.0" + version: "10.4.0" frontend_server_client: dependency: transitive description: @@ -581,18 +581,18 @@ packages: dependency: "direct main" description: name: image_picker - sha256: f98d76672d309c8b7030c323b3394669e122d52b307d2bbd8d06bd70f5b2aabe + sha256: d39cc12402dab8365fe5b5370e64694ae0223d675c36b15ff0490b7cc3d32551 url: "https://pub.dev" source: hosted - version: "0.8.6+1" + version: "0.8.6+2" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: b1cbfec0f5aef427a18eb573f5445af8c9c568626bf3388553e40c263d3f7368 + sha256: "385f12ee9c7288575572c7873a332016ec45ebd092e1c2f6bd421b4a9ad21f1d" url: "https://pub.dev" source: hosted - version: "0.8.5+5" + version: "0.8.5+6" image_picker_for_web: dependency: transitive description: @@ -605,10 +605,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: "39c013200046d14c58b71dc4fa3d00e425fc9c699d589136cd3ca018727c0493" + sha256: "884ed71165bc01ffe1b0b7813e6fa17e1e9442da974656f99b79a292371303d6" url: "https://pub.dev" source: hosted - version: "0.8.6+6" + version: "0.8.6+8" image_picker_platform_interface: dependency: transitive description: @@ -661,10 +661,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: "040088d9eb2337f3a51ddabe35261e2fea1c351e3dd29d755ed1290b6b700a75" + sha256: dadc08bd61f72559f938dd08ec20dbfec6c709bba83515085ea943d2078d187a url: "https://pub.dev" source: hosted - version: "6.6.0" + version: "6.6.1" lints: dependency: transitive description: @@ -685,18 +685,18 @@ packages: dependency: transitive description: name: logging - sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946 + sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" markdown: dependency: transitive description: name: markdown - sha256: c2b81e184067b41d0264d514f7cdaa2c02d38511e39d6521a1ccc238f6d7b3f2 + sha256: b3c60dee8c2af50ad0e6e90cceba98e47718a6ee0a7a6772c77846a0cc21f78b url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "7.0.1" matcher: dependency: transitive description: @@ -789,10 +789,10 @@ packages: dependency: transitive description: name: path_provider_linux - sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 + sha256: "2e32f1640f07caef0d3cb993680f181c79e54a3827b997d5ee221490d131fbd9" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.8" path_provider_platform_interface: dependency: transitive description: @@ -1018,10 +1018,10 @@ packages: dependency: transitive description: name: source_gen - sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d" + sha256: c2bea18c95cfa0276a366270afaa2850b09b4a76db95d546f3d003dcc7011298 url: "https://pub.dev" source: hosted - version: "1.2.6" + version: "1.2.7" source_helper: dependency: transitive description: @@ -1131,18 +1131,18 @@ packages: dependency: transitive description: name: universal_io - sha256: "79f78ddad839ee3aae3ec7c01eb4575faf0d5c860f8e5223bc9f9c17f7f03cef" + sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d" url: "https://pub.dev" source: hosted - version: "2.0.4" + version: "2.2.0" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: "698fa0b4392effdc73e9e184403b627362eb5fbf904483ac9defbb1c2191d809" + sha256: e8f2efc804810c0f2f5b485f49e7942179f56eabcfe81dce3387fec4bb55876b url: "https://pub.dev" source: hosted - version: "6.1.8" + version: "6.1.9" url_launcher_android: dependency: transitive description: @@ -1155,10 +1155,10 @@ packages: dependency: transitive description: name: url_launcher_ios - sha256: bb328b24d3bccc20bdf1024a0990ac4f869d57663660de9c936fb8c043edefe3 + sha256: "0a5af0aefdd8cf820dd739886efb1637f1f24489900204f50984634c07a54815" url: "https://pub.dev" source: hosted - version: "6.0.18" + version: "6.1.0" url_launcher_linux: dependency: transitive description: @@ -1387,10 +1387,10 @@ packages: dependency: transitive description: name: xdg_directories - sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 + sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 url: "https://pub.dev" source: hosted - version: "0.2.0+3" + version: "1.0.0" xml: dependency: transitive description: @@ -1409,4 +1409,4 @@ packages: version: "3.1.1" sdks: dart: ">=2.18.0 <4.0.0" - flutter: ">=3.1.0-0" + flutter: ">=3.3.0" From d59db8f4bdd719c85a590ad8b527b79981c64641 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 22 Feb 2023 18:18:37 +0530 Subject: [PATCH 167/466] final touches before release --- .DS_Store | Bin 10244 -> 10244 bytes .flutter-plugins-dependencies | 2 +- android/app/src/main/assets/index.html | 30 ++++------ .../kotlin/com/example/acela/MainActivity.kt | 56 +++++++++++++----- ios/Runner/public/index.html | 30 ++++------ .../update_video/video_details_info.dart | 4 ++ 6 files changed, 67 insertions(+), 55 deletions(-) diff --git a/.DS_Store b/.DS_Store index fbafe4b56b6548fc4ef86d1faf89dab691ab51cf..23c4ae947c095b4679da419b221f9a75d5b986d7 100644 GIT binary patch delta 62 xcmZn(XbIS$FE-gvxRl+{Oh>`Uz-00oF`3EFgjF`b5tHWJ%%-5phC^185ddD069NDL delta 82 zcmZn(XbIS$FUGiYvVmA3w`6s-p{a$Af}xSw + MethodChannel( + flutterEngine.dartExecutor.binaryMessenger, "blog.hive.auth/bridge" + ).setMethodCallHandler { call, result -> + this.result = result + val username = call.argument("username") + val authKey = call.argument("authKey") + val data = call.argument("data") + if (call.method == "getRedirectUriData" && username != null) { + webView?.evaluateJavascript("getRedirectUriData('$username');", null) + } else if (call.method == "getDecryptedHASToken" && username != null && authKey != null && data != null) { + webView?.evaluateJavascript("getDecryptedHASToken('$username','$authKey','$data');", null) + } + } + MethodChannel( + flutterEngine.dartExecutor.binaryMessenger, + "com.example.acela/auth" + ).setMethodCallHandler { call, result -> this.result = result val username = call.argument("username") val postingKey = call.argument("postingKey") @@ -76,15 +89,23 @@ class MainActivity: FlutterActivity() { if (call.method == "validate" && username != null && postingKey != null) { webView?.evaluateJavascript("validateHiveKey('$username','$postingKey');", null) } else if (call.method == "encryptedToken" && username != null - && postingKey != null && encryptedToken != null) { - webView?.evaluateJavascript("decryptMemo('$username','$postingKey', '$encryptedToken');", null) - } else if (call.method == "postVideo" && data != null && postingKey != null ) { + && postingKey != null && encryptedToken != null + ) { + webView?.evaluateJavascript( + "decryptMemo('$username','$postingKey', '$encryptedToken');", + null + ) + } else if (call.method == "postVideo" && data != null && postingKey != null) { webView?.evaluateJavascript("postVideo('$data','$postingKey');", null) } else if (call.method == "newPostVideo" && thumbnail != null && video_v2 != null && description != null && title != null && tags != null && username != null && permlink != null && duration != null && size != null && originalFilename != null - && firstUpload != null && bene != null && beneW != null && community != null && ipfsHash != null) { - webView?.evaluateJavascript("newPostVideo('$thumbnail','$video_v2', '$description', '$title', '$tags', '$username', '$permlink', $duration, $size, '$originalFilename', 'en', $firstUpload, '$bene', '$beneW', '$postingKey', '$community', '$ipfsHash');", null) + && firstUpload != null && bene != null && beneW != null && community != null && ipfsHash != null + ) { + webView?.evaluateJavascript( + "newPostVideo('$thumbnail','$video_v2', '$description', '$title', '$tags', '$username', '$permlink', $duration, $size, '$originalFilename', 'en', $firstUpload, '$bene', '$beneW', '$postingKey', '$community', '$ipfsHash');", + null + ) } } } @@ -103,7 +124,7 @@ class MainActivity: FlutterActivity() { val assetLoader = WebViewAssetLoader.Builder() .addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(this)) .build() - val client: WebViewClient = object: WebViewClient() { + val client: WebViewClient = object : WebViewClient() { @RequiresApi(Build.VERSION_CODES.LOLLIPOP) override fun shouldInterceptRequest( view: WebView, @@ -133,12 +154,17 @@ class WebAppInterface(private val mContext: Context) { val dataObject = gson.fromJson(message, JSEvent::class.java) when (dataObject.type) { JSBridgeAction.VALIDATE_HIVE_KEY.value -> { - // now respond back to flutter + main.result?.success(message) + } + JSBridgeAction.GET_REDIRECT_URI_DATA.value -> { main.result?.success(message) } JSBridgeAction.DECRYPTED_MEMO.value -> { main.result?.success(message) } + JSBridgeAction.GET_DECRYPTED_HAS_TOKEN.value -> { + main.result?.success(message) + } JSBridgeAction.POST_VIDEO.value -> { main.result?.success(message) } @@ -146,12 +172,14 @@ class WebAppInterface(private val mContext: Context) { } } -data class JSEvent ( +data class JSEvent( val type: String, ) enum class JSBridgeAction(val value: String) { VALIDATE_HIVE_KEY("validateHiveKey"), DECRYPTED_MEMO("decryptedMemo"), - POST_VIDEO("postVideo") + POST_VIDEO("postVideo"), + GET_REDIRECT_URI_DATA("getRedirectUriData"), + GET_DECRYPTED_HAS_TOKEN("getDecryptedHASToken"), } diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index 97d6d47a..bd75d32d 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -37,25 +37,21 @@ console.log("PubWif: ", pubWif); const Valid = hive.auth.wifIsValid(postingKey, pubWif); console.log(`is valid ${Valid}`); - var result = { + replyToNative({ type: "validateHiveKey", valid: Valid, accountName: accountName, error: "", - }; - window.webkit.messageHandlers.acela.postMessage(result); - // Android.postMessage(JSON.stringify(result)); + }); }) .catch(function (err) { console.log("Error: ", err); - var result = { + replyToNative({ type: "validateHiveKey", valid: false, accountName: accountName, error: err.message, - }; - window.webkit.messageHandlers.acela.postMessage(result); - // Android.postMessage(JSON.stringify(result)); + }); }); } @@ -71,25 +67,21 @@ const Valid = hive.auth.wifIsValid(postingKey, pubWif); console.log(`is valid ${Valid}`); let decrypted = hive.memo.decode(postingKey, encrypted); - let result = { + replyToNative({ type: "decryptedMemo", accountName: accountName, decrypted: decrypted, error: "", - }; - window.webkit.messageHandlers.acela.postMessage(result); - // Android.postMessage(JSON.stringify(result)); + }); }) .catch(function (err) { console.log("Error: ", err); - let result = { + replyToNative({ type: "decryptedMemo", accountName: accountName, decrypted: "", error: err.message, - }; - window.webkit.messageHandlers.acela.postMessage(result); - // Android.postMessage(JSON.stringify(result)); + }); }); } @@ -404,13 +396,11 @@ }) .catch(function (err) { console.error(err); - var result = { + replyToNative({ type: "postVideo", valid: false, error: err.message, - }; - window.webkit.messageHandlers.acela.postMessage(result); - //Android.postMessage(JSON.stringify(result)); + }); }); } diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index 14685bdd..40913274 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -6,6 +6,7 @@ import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/screens/communities_screen/communities_screen.dart'; +import 'package:acela/src/screens/my_account/my_account_screen.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/safe_convert.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; @@ -197,8 +198,11 @@ class _VideoDetailsInfoState extends State { if (widget.justForEditing) { setState(() { showMessage('Video details are saved.'); + var screen = MyAccountScreen(); Navigator.of(context).pop(); Navigator.of(context).pop(); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); return; }); } From 383d4f38130cfa7b96c984ea756baa248b85dc3d Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 24 Feb 2023 20:29:23 +0530 Subject: [PATCH 168/466] fix for community selection on 3Shorts --- .flutter-plugins-dependencies | 2 +- android/.idea/gradle.xml | 33 ++++----- android/.idea/misc.xml | 3 +- android/.idea/modules.xml | 72 ------------------- android/.idea/modules/android.iml | 18 ----- .../update_video/video_details_info.dart | 11 +-- pubspec.yaml | 2 +- 7 files changed, 27 insertions(+), 114 deletions(-) delete mode 100644 android/.idea/modules.xml delete mode 100644 android/.idea/modules/android.iml diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 7de48f25..f6f1516d 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+8/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.1.0/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+6/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.8/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-02-22 18:15:47.492233","version":"3.7.0-1.5.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.6+8/","native_build":true,"dependencies":[]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_apple-9.0.7/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_ios-6.1.0/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.3.8/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-2.9.5/","native_build":true,"dependencies":[]}],"android":[{"name":"better_player","path":"/Users/sagar/.pub-cache/git/betterplayer-91a9625524cdff448e0a9deb5047bcf20cc8dcf1/","native_build":true,"dependencies":["wakelock"]},{"name":"device_info_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus-4.1.3/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage-6.1.0/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_android-0.8.5+6/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"images_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/images_picker-1.2.11/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_android-10.2.0/","native_build":true,"dependencies":[]},{"name":"share_plus","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus-4.5.3/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.23/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_android-2.3.10/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]},{"name":"wakelock","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock-0.6.2/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sagar/.pub-cache/hosted/pub.dev/webview_flutter_android-2.10.4/","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_macos-3.0.0/","native_build":true,"dependencies":[]},{"name":"ffmpeg_kit_flutter","path":"/Users/sagar/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-4.5.1/","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-1.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]},{"name":"share_plus_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_macos-3.0.1/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.2/","native_build":true,"dependencies":[]},{"name":"video_compress","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_compress-3.1.2/","native_build":true,"dependencies":[]},{"name":"wakelock_macos","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_macos-0.4.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_linux-3.0.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.8/","native_build":false,"dependencies":[]},{"name":"share_plus_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_linux-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_linux","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.2/","native_build":true,"dependencies":[]}],"windows":[{"name":"device_info_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_windows-4.1.0/","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-1.1.3/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.2/","native_build":true,"dependencies":[]},{"name":"share_plus_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_windows-3.0.1/","native_build":false,"dependencies":[]},{"name":"url_launcher_windows","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.3/","native_build":true,"dependencies":[]}],"web":[{"name":"device_info_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/device_info_plus_web-3.0.0/","dependencies":[]},{"name":"file_picker","path":"/Users/sagar/.pub-cache/hosted/pub.dev/file_picker-5.2.5/","dependencies":[]},{"name":"flutter_secure_storage_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.1.1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.10/","dependencies":[]},{"name":"share_plus_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/share_plus_web-3.1.0/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.14/","dependencies":[]},{"name":"video_player_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web-2.0.13/","dependencies":[]},{"name":"video_player_web_hls","path":"/Users/sagar/.pub-cache/hosted/pub.dev/video_player_web_hls-0.1.11+6/","dependencies":[]},{"name":"wakelock_web","path":"/Users/sagar/.pub-cache/hosted/pub.dev/wakelock_web-0.4.0/","dependencies":[]}]},"dependencyGraph":[{"name":"better_player","dependencies":["wakelock","path_provider"]},{"name":"device_info_plus","dependencies":["device_info_plus_macos","device_info_plus_linux","device_info_plus_web","device_info_plus_windows"]},{"name":"device_info_plus_linux","dependencies":[]},{"name":"device_info_plus_macos","dependencies":[]},{"name":"device_info_plus_web","dependencies":[]},{"name":"device_info_plus_windows","dependencies":[]},{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"images_picker","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"share_plus","dependencies":["share_plus_linux","share_plus_macos","share_plus_windows","share_plus_web"]},{"name":"share_plus_linux","dependencies":["url_launcher"]},{"name":"share_plus_macos","dependencies":[]},{"name":"share_plus_web","dependencies":["url_launcher"]},{"name":"share_plus_windows","dependencies":["url_launcher"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_compress","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_player_web_hls","dependencies":[]},{"name":"video_thumbnail","dependencies":[]},{"name":"wakelock","dependencies":["wakelock_macos","wakelock_web"]},{"name":"wakelock_macos","dependencies":[]},{"name":"wakelock_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-02-24 20:19:21.326917","version":"3.7.0-1.5.pre"} \ No newline at end of file diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml index a8f648f2..95ad5161 100644 --- a/android/.idea/gradle.xml +++ b/android/.idea/gradle.xml @@ -1,6 +1,5 @@ -
\n\n" + + let body = + "
\n\n" + `[![](${thumbnail})](https://3speak.tv/watch?v=${author}/${permlink})\n\n` + `▶️ [Watch on 3Speak](https://3speak.tv/watch?v=${author}/${permlink})\n\n` + "
\n\n" + @@ -640,8 +652,8 @@ function getRedirectUriData(uname) { username = uname.toLowerCase(); const HAS_APP_DATA = { - name: "3Speak Mobile iOS App", - description: "3Speak Mobile iOS App with HAS Integration", + name: "3Speak Mobile Android App", + description: "3Speak Mobile Android App with HAS Integration", }; const auth_data = { app: HAS_APP_DATA, @@ -689,6 +701,58 @@ } } + function getEncryptedChallenge(username, authKey) { + try { + const challenge_data = { + key_type: "posting", + challenge: JSON.stringify({ + account: username, + ts: Date.now(), + }), + }; + const data = CryptoJS.AES.encrypt( + JSON.stringify(challenge_data), + auth_key + ).toString(); + replyToNative({ + type: "getEncryptedChallenge", + valid: true, + username: username, + error: "", + data: `${data}|${challenge_data.challenge}`, + }); + } catch (e) { + replyToNative({ + type: "getEncryptedChallenge", + valid: false, + accountName: username, + error: e.message, + }); + } + } + + function getDecryptedChallenge(username, authKey) { + try { + const decryptedData = JSON.parse( + CryptoJS.AES.decrypt(data, authKey).toString(CryptoJS.enc.Utf8) + ); + replyToNative({ + type: "getDecryptedChallenge", + valid: true, + username: username, + error: "", + data: decryptedData.challenge, + }); + } catch (e) { + replyToNative({ + type: "getDecryptedChallenge", + valid: false, + accountName: username, + error: e.message, + }); + } + } + function replyToNative(result) { window.webkit.messageHandlers.acela.postMessage(result); // Android.postMessage(JSON.stringify(result)); diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index 1431e7e4..c93091b7 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -110,6 +110,18 @@ class _HiveAuthLoginScreenState extends State loadingQR = false; }); break; + case "challenge_ack": + var messageData = asString(map, 'data'); + decryptData(widget.appData, messageData); + break; + case "challenge_nack": + showError("You denied signing the auth"); + setState(() { + qrCode = null; + timer = 0; + loadingQR = false; + }); + break; default: log('Default case here'); } @@ -217,64 +229,64 @@ class _HiveAuthLoginScreenState extends State didTapKeychainButton ? Container() : Column( - children: [ - const SizedBox(height: 10), - Image.asset('assets/hive_auth_button.png'), - const SizedBox(height: 10), - Text('Scan QR Code'), - SizedBox(height: 10), - InkWell( - child: Container( - decoration: BoxDecoration(color: Colors.white), - child: QrImageView( - data: qr, - size: 200, - gapless: true, - ), - ), - onTap: () { - var url = Uri.parse(qr); - launchUrl(url); - }, - ), - SizedBox(height: 10), - SizedBox( - width: 200, - child: LinearProgressIndicator( - value: timer.toDouble() / timeoutValue.toDouble(), - semanticsLabel: 'Timeout Timer for HiveAuth QR', - ), - ), - ], + children: [ + const SizedBox(height: 10), + Image.asset('assets/hive_auth_button.png'), + const SizedBox(height: 10), + Text('Scan QR Code'), + SizedBox(height: 10), + InkWell( + child: Container( + decoration: BoxDecoration(color: Colors.white), + child: QrImageView( + data: qr, + size: 200, + gapless: true, + ), ), + onTap: () { + var url = Uri.parse(qr); + launchUrl(url); + }, + ), + SizedBox(height: 10), + SizedBox( + width: 200, + child: LinearProgressIndicator( + value: timer.toDouble() / timeoutValue.toDouble(), + semanticsLabel: 'Timeout Timer for HiveAuth QR', + ), + ), + ], + ), didTapKeychainButton ? Column( - children: [ - const SizedBox(height: 10), - const Text( - 'Authorize this request with "Keychain for Hive" app.'), - const SizedBox(height: 20), - ElevatedButton( - onPressed: () { - var url = Uri.parse(qr); - launchUrl(url); - }, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black), - child: Image.asset('assets/hive-keychain-image.png', - width: 220), - ), - const SizedBox(height: 20), - SizedBox(height: 10), - SizedBox( - width: 200, - child: LinearProgressIndicator( - value: timer.toDouble() / timeoutValue.toDouble(), - semanticsLabel: 'Timeout Timer for HiveAuth QR', - ), - ), - ], - ) + children: [ + const SizedBox(height: 10), + const Text( + 'Authorize this request with "Keychain for Hive" app.'), + const SizedBox(height: 20), + ElevatedButton( + onPressed: () { + var url = Uri.parse(qr); + launchUrl(url); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black), + child: Image.asset('assets/hive-keychain-image.png', + width: 220), + ), + const SizedBox(height: 20), + SizedBox(height: 10), + SizedBox( + width: 200, + child: LinearProgressIndicator( + value: timer.toDouble() / timeoutValue.toDouble(), + semanticsLabel: 'Timeout Timer for HiveAuth QR', + ), + ), + ], + ) : Container() ], ), @@ -285,43 +297,43 @@ class _HiveAuthLoginScreenState extends State return loadingQR || isLoading ? const Center(child: CircularProgressIndicator()) : qrCode == null - ? Container( - margin: EdgeInsets.all(10), - child: Column( - children: [ - _hiveUserName(), - const SizedBox(height: 10), - _hasButton(appData), - const SizedBox(height: 10), - const Text('- OR -'), - const SizedBox(height: 10), - _hivePostingKey(), - const SizedBox(height: 10), - ElevatedButton( - onPressed: () { - onLoginTapped(appData); - }, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black), - child: const Text('Login with Posting Key'), - ), - const SizedBox(height: 10), - const Text('- OR -'), - const SizedBox(height: 10), - ElevatedButton( - onPressed: () { - const screen = SignUpScreen(); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - child: Text('Sign up'), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black), - ), - ], - ), - ) - : _showQRCodeAndKeychainButton(qrCode!); + ? Container( + margin: EdgeInsets.all(10), + child: Column( + children: [ + _hiveUserName(), + const SizedBox(height: 10), + _hasButton(appData), + const SizedBox(height: 10), + const Text('- OR -'), + const SizedBox(height: 10), + _hivePostingKey(), + const SizedBox(height: 10), + ElevatedButton( + onPressed: () { + onLoginTapped(appData); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black), + child: const Text('Login with Posting Key'), + ), + const SizedBox(height: 10), + const Text('- OR -'), + const SizedBox(height: 10), + ElevatedButton( + onPressed: () { + const screen = SignUpScreen(); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + child: Text('Sign up'), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black), + ), + ], + ), + ) + : _showQRCodeAndKeychainButton(qrCode!); } void onLoginTapped(HiveUserData appData) async { @@ -341,7 +353,7 @@ class _HiveAuthLoginScreenState extends State var bridgeResponse = LoginBridgeResponse.fromJsonString(response); if (bridgeResponse.valid) { var response = - await Communicator().login(usernameController.text, postingKey); + await Communicator().login(usernameController.text, postingKey); if (response.valid) { debugPrint("Successful login"); String resolution = await storage.read(key: 'resolution') ?? '480p'; @@ -377,7 +389,8 @@ class _HiveAuthLoginScreenState extends State var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).pushReplacement(route); showMessage( - 'You have successfully logged in as - ${usernameController.text}'); + 'You have successfully logged in as - ${usernameController + .text}'); setState(() { isLoading = false; }); @@ -432,7 +445,7 @@ class _HiveAuthLoginScreenState extends State void decryptData(HiveUserData data, String encryptedData) async { final String response = - await platform.invokeMethod('getDecryptedHASToken', { + await platform.invokeMethod('getDecryptedHASToken', { 'username': usernameController.text, 'authKey': authKey, 'data': encryptedData, @@ -469,19 +482,34 @@ class _HiveAuthLoginScreenState extends State language: data.language, ); server.updateHiveUserData(newData); - showMessage( - 'You have successfully logged in with Hive Auth with user - ${usernameController.text}'); - Navigator.of(context).pop(); - var screen = GQLFeedScreen( - appData: newData, - username: usernameController.text, - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).pushReplacement(route); + showMessage('You have successfully logged in with Hive Auth with user - ${usernameController.text}'); + final String eChallengeResponse = await platform.invokeMethod('getEncryptedChallenge', { + 'username': usernameController.text, + 'authKey': authKey, + }); + var eChallengeResponseData = json.decode(eChallengeResponse)['data'] as String; + var eData = eChallengeResponseData.split("|")[0]; + var challengeData = eChallengeResponseData.split("|")[1]; + var socketData = { + "cmd": "challenge_req", + "account": usernameController.text, + "token": tokenData[0], + "data": eData, + }; + var jsonEncodedData = json.encode(socketData); + socket.sink.add(jsonEncodedData); + // Navigator.of(context).pop(); + // var screen = GQLFeedScreen( + // appData: newData, + // username: usernameController.text, + // ); + // var route = MaterialPageRoute(builder: (c) => screen); + // Navigator.of(context).pushReplacement(route); } } else { showMessage( - 'Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); + 'Something went wrong - ${bridgeResponse + .error}. Please go back & try again.'); } } diff --git a/pubspec.yaml b/pubspec.yaml index 985af4f4..24eeddf5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.3.0+88 +version: 2.3.1+89 environment: sdk: ">=2.15.1 <3.0.0" From 4b372bc7a628e7b6c4d196e65ebfecac17ba9b0c Mon Sep 17 00:00:00 2001 From: sagar Date: Wed, 7 Feb 2024 17:07:23 +0530 Subject: [PATCH 361/466] brought back native video full screen for ios --- .../home_feed_video_full_screen_button.dart | 40 ++++++++++++++++--- .../widgets/new_feed_list_item.dart | 10 +++-- .../new_video_details_screen.dart | 10 ++--- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_full_screen_button.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_full_screen_button.dart index 9b0ad2ea..199ceb4e 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_full_screen_button.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_full_screen_button.dart @@ -1,14 +1,23 @@ +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/controller/home_feed_video_controller.dart'; +import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; import 'package:better_player/better_player.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; class HomeFeedVideoFullScreenButton extends StatelessWidget { const HomeFeedVideoFullScreenButton( - {Key? key, required this.betterPlayerController}) + {Key? key, + required this.betterPlayerController, + required this.item, + required this.appData}) : super(key: key); final BetterPlayerController betterPlayerController; + final GQLFeedItem item; + final HiveUserData appData; @override Widget build(BuildContext context) { @@ -18,12 +27,31 @@ class HomeFeedVideoFullScreenButton extends StatelessWidget { visible: isInitialized, child: IconButton( onPressed: () { - context - .read() - .changeControlsVisibility(betterPlayerController, true); - betterPlayerController.enterFullScreen(); + if (defaultTargetPlatform == TargetPlatform.android) { + context + .read() + .changeControlsVisibility(betterPlayerController, true); + betterPlayerController.enterFullScreen(); + } else { + fullscreenTapped(); + } }, - icon: Icon(Icons.fullscreen,color: Colors.white,)), + icon: Icon( + Icons.fullscreen, + color: Colors.white, + )), ); } + + void fullscreenTapped() async { + var position = await betterPlayerController.videoPlayerController?.position; + var seconds = position?.inSeconds; + if (seconds == null) return; + debugPrint('position is $position'); + const platform = MethodChannel('com.example.acela/auth'); + await platform.invokeMethod('playFullscreen', { + 'url': item.videoV2M3U8(appData), + 'seconds': seconds, + }); + } } diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart index 50c4222d..b7e1419c 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart @@ -122,12 +122,12 @@ class _NewFeedListItemState extends State fullScreenByDefault: false, controlsConfiguration: BetterPlayerControlsConfiguration( enablePip: false, - enableFullscreen: - true, //defaultTargetPlatform == TargetPlatform.android, + enableFullscreen: defaultTargetPlatform == TargetPlatform.android, enableSkips: true, enableMute: true), autoDetectFullscreenAspectRatio: false, - placeholder: !widget.item!.isVideo ? videoThumbnail() : const SizedBox.shrink(), + placeholder: + !widget.item!.isVideo ? videoThumbnail() : const SizedBox.shrink(), deviceOrientationsOnFullScreen: const [ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, @@ -177,7 +177,7 @@ class _NewFeedListItemState extends State _betterPlayerController, videoSettingProvider); } - Widget videoThumbnail(){ + Widget videoThumbnail() { return Selector( selector: (context, myType) => myType.resolution, builder: (context, value, child) { @@ -426,6 +426,8 @@ class _NewFeedListItemState extends State top: 5, left: 5, child: HomeFeedVideoFullScreenButton( + appData: widget.appData!, + item: widget.item!, betterPlayerController: _betterPlayerController!)); } diff --git a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart index e27a6933..f458e049 100644 --- a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart +++ b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart @@ -125,12 +125,13 @@ class _NewVideoDetailsScreenState extends State { } } - Widget videoThumbnail(){ + Widget videoThumbnail() { return Selector( selector: (context, myType) => myType.resolution, builder: (context, value, child) { return CachedImage( - imageUrl: Utilities.getProxyImage(value, (widget.item.spkvideo?.thumbnailUrl ?? '')), + imageUrl: Utilities.getProxyImage( + value, (widget.item.spkvideo?.thumbnailUrl ?? '')), imageHeight: 230, imageWidth: double.infinity, ); @@ -147,8 +148,7 @@ class _NewVideoDetailsScreenState extends State { placeholder: videoThumbnail(), controlsConfiguration: BetterPlayerControlsConfiguration( enablePip: false, - enableFullscreen: - true, //defaultTargetPlatform == TargetPlatform.android, + enableFullscreen: defaultTargetPlatform == TargetPlatform.android, enableSkips: true, ), autoDetectFullscreenAspectRatio: false, @@ -275,7 +275,7 @@ class _NewVideoDetailsScreenState extends State { backgroundColor: Colors.black.withOpacity(0.6), child: IconButton( onPressed: () { - _betterPlayerController.enterFullScreen(); + fullscreenTapped(); }, icon: Icon( Icons.fullscreen, From bd48a6846f2ee92a915a8099a94d297ef9b8e15c Mon Sep 17 00:00:00 2001 From: sagar Date: Thu, 8 Feb 2024 12:03:37 +0530 Subject: [PATCH 362/466] new play/pause button in home feed video , user settings merged with settings --- .../home_feed_video_controller.dart | 26 ++++ .../home_feed_video_full_screen_button.dart | 33 +++-- .../widgets/mute_unmute_button.dart | 27 ++-- .../widgets/new_feed_list_item.dart | 62 +++++--- .../widgets/play_pause_button.dart | 37 +++++ .../screens/my_account/my_account_screen.dart | 3 +- lib/src/screens/settings/settings_screen.dart | 140 +++++++++++++++++- .../new_video_details_screen.dart | 6 +- 8 files changed, 277 insertions(+), 57 deletions(-) create mode 100644 lib/src/screens/home_screen/home_screen_feed_item/widgets/play_pause_button.dart diff --git a/lib/src/screens/home_screen/home_screen_feed_item/controller/home_feed_video_controller.dart b/lib/src/screens/home_screen/home_screen_feed_item/controller/home_feed_video_controller.dart index 6ec4c496..3ec40e0b 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/controller/home_feed_video_controller.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/controller/home_feed_video_controller.dart @@ -8,6 +8,24 @@ class HomeFeedVideoController extends ChangeNotifier { bool skippedToInitialDuartion = false; bool isInitialized = false; bool isUserOnAnotherScreen = false; + bool isPaused = false; + + void videoEventListener( + BetterPlayerController? betterPlayerController, BetterPlayerEvent event) { + + if (event.betterPlayerEventType == BetterPlayerEventType.hideFullscreen && + !betterPlayerController!.videoPlayerController!.value.isPlaying && + !isUserOnAnotherScreen) { + changeControlsVisibility(betterPlayerController, false); + } + } + + void didPopFullScreen(BetterPlayerController betterPlayerController) { + if (!betterPlayerController.videoPlayerController!.value.isPlaying && + !isUserOnAnotherScreen) { + changeControlsVisibility(betterPlayerController, false); + } + } void videoPlayerListener(BetterPlayerController? betterPlayerController, VideoSettingProvider videoSettingProvider) { @@ -22,6 +40,14 @@ class HomeFeedVideoController extends ChangeNotifier { changeControlsVisibility(betterPlayerController, false); } } + if (betterPlayerController.videoPlayerController!.value.isPlaying && + isPaused) { + isPaused = false; + } else if (!betterPlayerController + .videoPlayerController!.value.isPlaying && + !isPaused) { + isPaused = true; + } if (totalDuration == null) { totalDuration = betterPlayerController.videoPlayerController!.value.duration!; diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_full_screen_button.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_full_screen_button.dart index 199ceb4e..c17e7f50 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_full_screen_button.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_full_screen_button.dart @@ -25,21 +25,24 @@ class HomeFeedVideoFullScreenButton extends StatelessWidget { .select((value) => value.isInitialized); return Visibility( visible: isInitialized, - child: IconButton( - onPressed: () { - if (defaultTargetPlatform == TargetPlatform.android) { - context - .read() - .changeControlsVisibility(betterPlayerController, true); - betterPlayerController.enterFullScreen(); - } else { - fullscreenTapped(); - } - }, - icon: Icon( - Icons.fullscreen, - color: Colors.white, - )), + child: CircleAvatar( + backgroundColor: Theme.of(context).primaryColorDark.withOpacity(0.5), + child: IconButton( + onPressed: () { + if (defaultTargetPlatform == TargetPlatform.android) { + context + .read() + .changeControlsVisibility(betterPlayerController, true); + betterPlayerController.enterFullScreen(); + } else { + fullscreenTapped(); + } + }, + icon: Icon( + Icons.fullscreen, + color: Colors.white, + )), + ), ); } diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/mute_unmute_button.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/mute_unmute_button.dart index 735ff97b..b55c9694 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/mute_unmute_button.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/mute_unmute_button.dart @@ -34,19 +34,22 @@ class _MuteUnmuteButtonState extends State { return Visibility( visible: isInitialized, - child: IconButton( - icon: Icon( - isMuted ? Icons.volume_off : Icons.volume_up, - color: Colors.white, + child: CircleAvatar( + backgroundColor: Theme.of(context).primaryColorDark.withOpacity(0.5), + child: IconButton( + icon: Icon( + isMuted ? Icons.volume_off : Icons.volume_up, + color: Colors.white, + ), + onPressed: () { + if (!isMuted) { + widget.betterPlayerController.setVolume(0); + } else { + widget.betterPlayerController.setVolume(1); + } + context.read().changeMuteStatus(!isMuted); + }, ), - onPressed: () { - if (!isMuted) { - widget.betterPlayerController.setVolume(0); - } else { - widget.betterPlayerController.setVolume(1); - } - context.read().changeMuteStatus(!isMuted); - }, ), ); } diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart index b7e1419c..c6e391f9 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart @@ -1,21 +1,23 @@ import 'dart:io'; + import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/image_resolution_provider.dart'; import 'package:acela/src/global_provider/video_setting_provider.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/home_screen/home_screen_feed_item/controller/home_feed_video_controller.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_full_screen_button.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_slider.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_timer.dart'; -import 'package:acela/src/screens/video_details_screen/new_video_details/video_detail_favourite_provider.dart'; -import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; -import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/mute_unmute_button.dart'; +import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/play_pause_button.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart'; +import 'package:acela/src/screens/video_details_screen/new_video_details/video_detail_favourite_provider.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/cached_image.dart'; -import 'package:acela/src/screens/home_screen/home_screen_feed_item/controller/home_feed_video_controller.dart'; -import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/mute_unmute_button.dart'; import 'package:acela/src/widgets/upvote_button.dart'; import 'package:better_player/better_player.dart'; import 'package:flutter/foundation.dart'; @@ -103,6 +105,7 @@ class _NewFeedListItemState extends State homeFeedVideoController.skippedToInitialDuartion = false; _betterPlayerController!.videoPlayerController! .removeListener(videoPlayerListener); + _betterPlayerController!.removeEventsListener(videoEventListener); homeFeedVideoController.reset(); _betterPlayerController!.videoPlayerController?.dispose(); _betterPlayerController!.dispose(); @@ -117,6 +120,18 @@ class _NewFeedListItemState extends State ) { BetterPlayerConfiguration betterPlayerConfiguration = BetterPlayerConfiguration( + routePageBuilder: + (context, animation, secondaryAnimation, controllerProvider) => + PopScope( + onPopInvoked: (didPop) { + if (didPop) { + homeFeedVideoController.didPopFullScreen(_betterPlayerController!); + } + }, + child: BetterPlayer( + controller: _betterPlayerController!, + ), + ), fit: BoxFit.contain, autoPlay: true, fullScreenByDefault: false, @@ -170,6 +185,7 @@ class _NewFeedListItemState extends State } _betterPlayerController!.videoPlayerController! .addListener(videoPlayerListener); + _betterPlayerController!.addEventsListener(videoEventListener); } void videoPlayerListener() { @@ -177,6 +193,10 @@ class _NewFeedListItemState extends State _betterPlayerController, videoSettingProvider); } + void videoEventListener(BetterPlayerEvent event) { + homeFeedVideoController.videoEventListener(_betterPlayerController, event); + } + Widget videoThumbnail() { return Selector( selector: (context, myType) => myType.resolution, @@ -209,8 +229,7 @@ class _NewFeedListItemState extends State _thumbNailAndLoader(thumbnail), _nextScreenGestureDetector(), _videoSlider(), - _muteUnMuteButton(), - _fullScreenButton(), + _interactionTools() ], ) : thumbnail, @@ -421,16 +440,6 @@ class _NewFeedListItemState extends State } } - Positioned _fullScreenButton() { - return Positioned( - top: 5, - left: 5, - child: HomeFeedVideoFullScreenButton( - appData: widget.appData!, - item: widget.item!, - betterPlayerController: _betterPlayerController!)); - } - Positioned _timer() { return Positioned( bottom: 10, @@ -439,11 +448,24 @@ class _NewFeedListItemState extends State ); } - Positioned _muteUnMuteButton() { + Positioned _interactionTools() { return Positioned( - right: 5, top: 5, - child: MuteUnmuteButton(betterPlayerController: _betterPlayerController!), + right: 5, + child: Column( + children: [ + HomeFeedVideoFullScreenButton( + appData: widget.appData!, + item: widget.item!, + betterPlayerController: _betterPlayerController!), + Padding( + padding: const EdgeInsets.symmetric(vertical: 5), + child: MuteUnmuteButton( + betterPlayerController: _betterPlayerController!), + ), + PlayPauseButton(betterPlayerController: _betterPlayerController!) + ], + ), ); } diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/play_pause_button.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/play_pause_button.dart new file mode 100644 index 00000000..6eff5bb9 --- /dev/null +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/play_pause_button.dart @@ -0,0 +1,37 @@ +import 'package:acela/src/screens/home_screen/home_screen_feed_item/controller/home_feed_video_controller.dart'; +import 'package:better_player/better_player.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class PlayPauseButton extends StatelessWidget { + const PlayPauseButton({Key? key, required this.betterPlayerController}) : super(key: key); + + final BetterPlayerController betterPlayerController; + + @override + Widget build(BuildContext context) { + bool isInitialized = context + .select((value) => value.isInitialized); + bool isPaused = context + .select((value) => value.isPaused); + return Visibility( + visible: isInitialized, + child: CircleAvatar( + backgroundColor: Theme.of(context).primaryColorDark.withOpacity(0.5), + child: IconButton( + icon: Icon( + !isPaused ? Icons.pause : Icons.play_arrow, + color: Colors.white, + ), + onPressed: () { + if (isPaused) { + betterPlayerController.play(); + } else { + betterPlayerController.pause(); + } + }, + ), + ), + ); + } +} diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index cacdd1c2..8fc4bc2c 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -6,6 +6,7 @@ import 'package:acela/src/screens/my_account/account_settings/account_settings_s import 'package:acela/src/screens/my_account/update_thumb/update_thumb_screen.dart'; import 'package:acela/src/screens/my_account/update_video/video_primary_info.dart'; import 'package:acela/src/screens/my_account/video_preview.dart'; +import 'package:acela/src/screens/settings/settings_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; @@ -98,7 +99,7 @@ class _MyAccountScreenState extends State ), IconButton( onPressed: () { - var screen = const AccountSettingsScreen(); + var screen = const SettingsScreen(isUserFromUserSettings: true,); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); }, diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index cc35a4e9..eef05074 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -2,7 +2,10 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/image_resolution_provider.dart'; import 'package:acela/src/global_provider/ipfs_node_provider.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/home_screen/new_home_screen.dart'; +import 'package:acela/src/screens/my_account/account_settings/widgets/delete_dialog.dart'; import 'package:acela/src/screens/settings/add_cutom_union_indexer.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/foundation.dart'; @@ -24,7 +27,10 @@ class VideoLanguage { } class SettingsScreen extends StatefulWidget { - const SettingsScreen({Key? key}) : super(key: key); + const SettingsScreen({Key? key, this.isUserFromUserSettings = false}) + : super(key: key); + + final bool isUserFromUserSettings; @override State createState() => _SettingsScreenState(); @@ -51,6 +57,7 @@ class _SettingsScreenState extends State { VideoLanguage(code: "he", name: "עִברִית"), VideoLanguage(code: "all", name: "All"), ]; + bool isLoading = false; @override void initState() { @@ -219,6 +226,113 @@ class _SettingsScreenState extends State { ); } + Widget _logout() { + var data = context.read(); + return Visibility( + visible: data.username != null, + child: ListTile( + leading: const Icon(Icons.logout), + title: const Text('Log Out'), + onTap: () { + logout(data); + }, + ), + ); + } + + Future logout(HiveUserData data) async { + // Create storage + const storage = FlutterSecureStorage(); + await storage.delete(key: 'username'); + await storage.delete(key: 'postingKey'); + await storage.delete(key: 'cookie'); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); + String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + String union = + await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; + String? lang = await storage.read(key: 'lang'); + var newUserData = HiveUserData( + username: null, + postingKey: null, + keychainData: null, + cookie: null, + resolution: resolution, + rpc: rpc, + union: union, + loaded: true, + language: lang, + ); + server.updateHiveUserData(newUserData); + if (widget.isUserFromUserSettings) { + Navigator.of(context).pop(); + } + Navigator.of(context).pop(); + Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (context) => + GQLFeedScreen(appData: newUserData, username: null), + ), + ); + } + + Widget _deleteAccount() { + var data = context.read(); + return Visibility( + visible: data.username != null, + child: ListTile( + leading: const Icon( + Icons.delete, + color: Colors.red, + ), + title: const Text( + 'Delete Account', + style: TextStyle(color: Colors.red), + ), + onTap: () { + _deleteDialog(data); + }, + ), + ); + } + + void _deleteDialog(HiveUserData data) { + showDialog( + barrierDismissible: true, + useRootNavigator: true, + context: context, + builder: (context) { + return DeleteDialog( + onDelete: () async { + Navigator.pop(context); + try { + setState(() { + isLoading = true; + }); + bool status = await Communicator().deleteAccount(data); + if (status) { + await logout(data); + showMessage('Account Deleted Successfully'); + } else { + showError("Sorry, Something went wrong."); + } + setState(() { + isLoading = false; + }); + } catch (e) { + setState(() { + isLoading = false; + }); + showError("Sorry, Something went wrong."); + } + }, + ); + }, + ); + } + Widget _changeLanguage(BuildContext context) { var data = Provider.of(context); var display = @@ -270,7 +384,7 @@ class _SettingsScreenState extends State { selector: (_, myType) => myType.autoPlayVideo, builder: (context, value, child) { return ListTile( - contentPadding: EdgeInsets.only(left: 15,right: 10), + contentPadding: EdgeInsets.only(left: 15, right: 10), leading: const Icon(Icons.auto_mode_rounded), title: const Text("Auto Play Video"), trailing: Transform.scale( @@ -283,7 +397,7 @@ class _SettingsScreenState extends State { ), ), onTap: () async { - settingsProvider.autoPlayVideo = !settingsProvider.autoPlayVideo; + settingsProvider.autoPlayVideo = !settingsProvider.autoPlayVideo; }, ); }, @@ -526,6 +640,16 @@ class _SettingsScreenState extends State { ); } + void showMessage(String string) { + var snackBar = SnackBar(content: Text(string)); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + void showError(String string) { + var snackBar = SnackBar(content: Text('Error: $string')); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + Widget _drawerMenu(BuildContext context, HiveUserData user) { return ListView( children: [ @@ -547,6 +671,10 @@ class _SettingsScreenState extends State { _divider(), _appVersion(context), _divider(), + _logout(), + _divider(), + _deleteAccount(), + _divider() ], ); } @@ -558,7 +686,11 @@ class _SettingsScreenState extends State { appBar: AppBar( title: const Text('Settings'), ), - body: _drawerMenu(context, user), + body: isLoading + ? Center( + child: CircularProgressIndicator(), + ) + : _drawerMenu(context, user), ); } } diff --git a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart index f458e049..7e665428 100644 --- a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart +++ b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart @@ -353,6 +353,7 @@ class _NewVideoDetailsScreenState extends State { } void showVoters() { + _betterPlayerController.pause(); List voters = []; bool currentUserPresentInVoters = false; if (postInfo != null) { @@ -698,11 +699,6 @@ class _NewVideoDetailsScreenState extends State { void changeControlsVisibility(bool showControls) { if (widget.betterPlayerController != null) { - if (!showControls) { - if (!widget.betterPlayerController!.isPlaying()!) { - widget.betterPlayerController!.videoPlayerController!.play(); - } - } widget.betterPlayerController!.setControlsAlwaysVisible(false); widget.betterPlayerController!.setControlsEnabled(showControls); widget.betterPlayerController!.setControlsVisibility(showControls); From 41a4c62b6d401d037cba2f2b0632f46ddb941c57 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 9 Feb 2024 08:07:19 +0530 Subject: [PATCH 363/466] acela core based login - work in progress --- ios/Runner/AcelaWebViewController.swift | 13 + ios/Runner/Bridges/Auth/HASBridge.swift | 14 ++ ios/Runner/public/index.html | 2 +- lib/main.dart | 5 +- .../models/user_stream/hive_user_stream.dart | 5 +- lib/src/screens/login/ha_login_screen.dart | 235 ++++++++++-------- .../hive_upvote_dialog.dart | 117 +++++---- lib/src/utils/communicator.dart | 9 +- lib/src/widgets/story_player.dart | 1 + lib/src/widgets/upvote_button.dart | 1 + 10 files changed, 238 insertions(+), 164 deletions(-) diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index 6fe35267..ef9e94fb 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -28,6 +28,7 @@ class AcelaWebViewController: UIViewController { var getHtmlHandler: ((String) -> Void)? = nil var getProofOfPayloadHandler: ((String) -> Void)? = nil var getEncryptedChallengeHandler: ((String) -> Void)? = nil + var getDecryptedChallengeHandler: ((String) -> Void)? = nil override func viewDidLoad() { super.viewDidLoad() @@ -152,6 +153,13 @@ class AcelaWebViewController: UIViewController { } } + func getDecryptedChallenge(username: String, authKey: String, data: String, handler: @escaping (String) -> Void) { + getDecryptedChallengeHandler = handler + OperationQueue.main.addOperation { + self.webView?.evaluateJavaScript("getDecryptedChallenge('\(username)','\(authKey)', '\(data)');") + } + } + func postPodcast( thumbnail: String, enclosureUrl: String, @@ -298,6 +306,11 @@ extension AcelaWebViewController: WKScriptMessageHandler { let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) else { return } getEncryptedChallengeHandler?(response) + case "getDecryptedChallenge": + guard + let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) + else { return } + getDecryptedChallengeHandler?(response) default: debugPrint("Do nothing here.") } } diff --git a/ios/Runner/Bridges/Auth/HASBridge.swift b/ios/Runner/Bridges/Auth/HASBridge.swift index 2ff54c6b..a0cd8609 100644 --- a/ios/Runner/Bridges/Auth/HASBridge.swift +++ b/ios/Runner/Bridges/Auth/HASBridge.swift @@ -73,6 +73,20 @@ class HASBridge { acela.getEncryptedChallenge(username: username, authKey: authKey) { data in result(data) } + case "getDecryptedChallenge": + guard + let arguments = call.arguments as? NSDictionary, + let username = arguments ["username"] as? String, + let authKey = arguments["authKey"] as? String, + let data = arguments["data"] as? String, + let acela = acela + else { + result(FlutterMethodNotImplemented) + return + } + acela.getDecryptedChallenge(username: username, authKey: authKey, data: data) { data in + result(data) + } default: result(FlutterMethodNotImplemented) } diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index b1fe69d9..b6db98ab 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -731,7 +731,7 @@ } } - function getDecryptedChallenge(username, authKey) { + function getDecryptedChallenge(username, authKey, data) { try { const decryptedData = JSON.parse( CryptoJS.AES.decrypt(data, authKey).toString(CryptoJS.enc.Utf8) diff --git a/lib/main.dart b/lib/main.dart index 25694f68..737e6dc2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -111,7 +111,7 @@ class _MyAppState extends State { initialData: HiveUserData( resolution: '480p', keychainData: null, - cookie: null, + accessToken: null, postingKey: null, username: null, rpc: 'api.hive.blog', @@ -141,6 +141,7 @@ class _MyAppState extends State { String? username = await storage.read(key: 'username'); String? postingKey = await storage.read(key: 'postingKey'); String? cookie = await storage.read(key: 'cookie'); + String? accessToken = await storage.read(key: 'accessToken'); String? hasId = await storage.read(key: 'hasId'); String? hasExpiry = await storage.read(key: 'hasExpiry'); String? hasAuthKey = await storage.read(key: 'hasAuthKey'); @@ -170,7 +171,7 @@ class _MyAppState extends State { hasId: hasId, ) : null, - cookie: cookie, + accessToken: accessToken, resolution: resolution, rpc: rpc, union: union, diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index 090df429..6730edbb 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -22,19 +22,20 @@ class HiveSocketData { class HiveUserData { String? username; String? postingKey; - String? cookie; + // String? cookie; String? language; HiveKeychainData? keychainData; String resolution; String rpc; String union; bool loaded; + String? accessToken; HiveUserData({ required this.username, required this.postingKey, required this.keychainData, - required this.cookie, + required this.accessToken, required this.resolution, required this.rpc, required this.union, diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index c93091b7..9f114ba9 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -35,6 +35,7 @@ class _HiveAuthLoginScreenState extends State var usernameController = TextEditingController(); late WebSocketChannel socket; String authKey = ''; + String proofOfPayload = ''; String? qrCode; var loadingQR = false; var timer = 0; @@ -112,11 +113,12 @@ class _HiveAuthLoginScreenState extends State break; case "challenge_ack": var messageData = asString(map, 'data'); - decryptData(widget.appData, messageData); + decryptChallenge(widget.appData, messageData); break; case "challenge_nack": - showError("You denied signing the auth"); + showError("You denied signing the auth"); setState(() { + proofOfPayload = ''; qrCode = null; timer = 0; loadingQR = false; @@ -229,64 +231,64 @@ class _HiveAuthLoginScreenState extends State didTapKeychainButton ? Container() : Column( - children: [ - const SizedBox(height: 10), - Image.asset('assets/hive_auth_button.png'), - const SizedBox(height: 10), - Text('Scan QR Code'), - SizedBox(height: 10), - InkWell( - child: Container( - decoration: BoxDecoration(color: Colors.white), - child: QrImageView( - data: qr, - size: 200, - gapless: true, - ), - ), - onTap: () { - var url = Uri.parse(qr); - launchUrl(url); - }, - ), - SizedBox(height: 10), - SizedBox( - width: 200, - child: LinearProgressIndicator( - value: timer.toDouble() / timeoutValue.toDouble(), - semanticsLabel: 'Timeout Timer for HiveAuth QR', + children: [ + const SizedBox(height: 10), + Image.asset('assets/hive_auth_button.png'), + const SizedBox(height: 10), + Text('Scan QR Code'), + SizedBox(height: 10), + InkWell( + child: Container( + decoration: BoxDecoration(color: Colors.white), + child: QrImageView( + data: qr, + size: 200, + gapless: true, + ), + ), + onTap: () { + var url = Uri.parse(qr); + launchUrl(url); + }, + ), + SizedBox(height: 10), + SizedBox( + width: 200, + child: LinearProgressIndicator( + value: timer.toDouble() / timeoutValue.toDouble(), + semanticsLabel: 'Timeout Timer for HiveAuth QR', + ), + ), + ], ), - ), - ], - ), didTapKeychainButton ? Column( - children: [ - const SizedBox(height: 10), - const Text( - 'Authorize this request with "Keychain for Hive" app.'), - const SizedBox(height: 20), - ElevatedButton( - onPressed: () { - var url = Uri.parse(qr); - launchUrl(url); - }, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black), - child: Image.asset('assets/hive-keychain-image.png', - width: 220), - ), - const SizedBox(height: 20), - SizedBox(height: 10), - SizedBox( - width: 200, - child: LinearProgressIndicator( - value: timer.toDouble() / timeoutValue.toDouble(), - semanticsLabel: 'Timeout Timer for HiveAuth QR', - ), - ), - ], - ) + children: [ + const SizedBox(height: 10), + const Text( + 'Authorize this request with "Keychain for Hive" app.'), + const SizedBox(height: 20), + ElevatedButton( + onPressed: () { + var url = Uri.parse(qr); + launchUrl(url); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black), + child: Image.asset('assets/hive-keychain-image.png', + width: 220), + ), + const SizedBox(height: 20), + SizedBox(height: 10), + SizedBox( + width: 200, + child: LinearProgressIndicator( + value: timer.toDouble() / timeoutValue.toDouble(), + semanticsLabel: 'Timeout Timer for HiveAuth QR', + ), + ), + ], + ) : Container() ], ), @@ -297,43 +299,43 @@ class _HiveAuthLoginScreenState extends State return loadingQR || isLoading ? const Center(child: CircularProgressIndicator()) : qrCode == null - ? Container( - margin: EdgeInsets.all(10), - child: Column( - children: [ - _hiveUserName(), - const SizedBox(height: 10), - _hasButton(appData), - const SizedBox(height: 10), - const Text('- OR -'), - const SizedBox(height: 10), - _hivePostingKey(), - const SizedBox(height: 10), - ElevatedButton( - onPressed: () { - onLoginTapped(appData); - }, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black), - child: const Text('Login with Posting Key'), - ), - const SizedBox(height: 10), - const Text('- OR -'), - const SizedBox(height: 10), - ElevatedButton( - onPressed: () { - const screen = SignUpScreen(); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - child: Text('Sign up'), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black), - ), - ], - ), - ) - : _showQRCodeAndKeychainButton(qrCode!); + ? Container( + margin: EdgeInsets.all(10), + child: Column( + children: [ + _hiveUserName(), + const SizedBox(height: 10), + _hasButton(appData), + const SizedBox(height: 10), + const Text('- OR -'), + const SizedBox(height: 10), + _hivePostingKey(), + const SizedBox(height: 10), + ElevatedButton( + onPressed: () { + onLoginTapped(appData); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black), + child: const Text('Login with Posting Key'), + ), + const SizedBox(height: 10), + const Text('- OR -'), + const SizedBox(height: 10), + ElevatedButton( + onPressed: () { + const screen = SignUpScreen(); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + child: Text('Sign up'), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black), + ), + ], + ), + ) + : _showQRCodeAndKeychainButton(qrCode!); } void onLoginTapped(HiveUserData appData) async { @@ -353,7 +355,7 @@ class _HiveAuthLoginScreenState extends State var bridgeResponse = LoginBridgeResponse.fromJsonString(response); if (bridgeResponse.valid) { var response = - await Communicator().login(usernameController.text, postingKey); + await Communicator().login(usernameController.text, postingKey); if (response.valid) { debugPrint("Successful login"); String resolution = await storage.read(key: 'resolution') ?? '480p'; @@ -389,8 +391,7 @@ class _HiveAuthLoginScreenState extends State var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).pushReplacement(route); showMessage( - 'You have successfully logged in as - ${usernameController - .text}'); + 'You have successfully logged in as - ${usernameController.text}'); setState(() { isLoading = false; }); @@ -443,9 +444,31 @@ class _HiveAuthLoginScreenState extends State socket.sink.close(); } + void decryptChallenge(HiveUserData data, String encryptedData) async { + final String response = + await platform.invokeMethod('getDecryptedChallenge', { + 'username': usernameController.text, + 'authKey': authKey, + 'data': encryptedData, + }); + var bridgeResponse = LoginBridgeResponse.fromJsonString(response); + if (bridgeResponse.valid && + bridgeResponse.data != null && + bridgeResponse.data!.isNotEmpty) { + var proof = bridgeResponse.data; + var payload = proofOfPayload; + setState(() { + proofOfPayload = ''; + }); + } else { + showMessage( + 'Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); + } + } + void decryptData(HiveUserData data, String encryptedData) async { final String response = - await platform.invokeMethod('getDecryptedHASToken', { + await platform.invokeMethod('getDecryptedHASToken', { 'username': usernameController.text, 'authKey': authKey, 'data': encryptedData, @@ -482,14 +505,19 @@ class _HiveAuthLoginScreenState extends State language: data.language, ); server.updateHiveUserData(newData); - showMessage('You have successfully logged in with Hive Auth with user - ${usernameController.text}'); - final String eChallengeResponse = await platform.invokeMethod('getEncryptedChallenge', { + showMessage( + 'You have successfully logged in with Hive Auth with user - ${usernameController.text}'); + final String eChallengeResponse = + await platform.invokeMethod('getEncryptedChallenge', { 'username': usernameController.text, 'authKey': authKey, }); - var eChallengeResponseData = json.decode(eChallengeResponse)['data'] as String; + var eChallengeResponseData = + json.decode(eChallengeResponse)['data'] as String; var eData = eChallengeResponseData.split("|")[0]; - var challengeData = eChallengeResponseData.split("|")[1]; + setState(() { + proofOfPayload = eChallengeResponseData.split("|")[1]; + }); var socketData = { "cmd": "challenge_req", "account": usernameController.text, @@ -508,8 +536,7 @@ class _HiveAuthLoginScreenState extends State } } else { showMessage( - 'Something went wrong - ${bridgeResponse - .error}. Please go back & try again.'); + 'Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); } } diff --git a/lib/src/screens/video_details_screen/hive_upvote_dialog.dart b/lib/src/screens/video_details_screen/hive_upvote_dialog.dart index 2fa36823..4b3559bf 100644 --- a/lib/src/screens/video_details_screen/hive_upvote_dialog.dart +++ b/lib/src/screens/video_details_screen/hive_upvote_dialog.dart @@ -24,6 +24,7 @@ class HiveUpvoteDialog extends StatefulWidget { required this.permlink, required this.hasKey, required this.hasAuthKey, + required this.accessToken, required this.activeVotes, required this.onClose, required this.onDone, @@ -33,6 +34,7 @@ class HiveUpvoteDialog extends StatefulWidget { final String permlink; final String hasKey; final String hasAuthKey; + final String? accessToken; final Function onDone; final Function onClose; final List activeVotes; @@ -237,61 +239,65 @@ class _HiveUpvoteDialogState extends State { setState(() { isUpVoting = true; }); - try { - var voteValue = sliderValue * 10000; - var user = data.username; - if (user == null) return; - const platform = MethodChannel('com.example.acela/auth'); - final String result = await platform.invokeMethod('voteContent', { - 'user': user, - 'author': widget.author, - 'permlink': widget.permlink, - 'weight': voteValue, - 'postingKey': data.postingKey ?? '', - 'hasKey': data.keychainData?.hasId ?? '', - 'hasAuthKey': data.keychainData?.hasAuthKey ?? '', - }); - var response = LoginBridgeResponse.fromJsonString(result); - if (response.valid && response.error.isEmpty) { - if (response.error == "" && - response.data != null && - response.data!.isNotEmpty && - data.keychainData?.hasAuthKey != null) { - var socketData = { - "cmd": "sign_req", - "account": data.username!, - "token": data.keychainData!.hasId, - "data": response.data!, - }; - loadingQR = true; - var jsonData = json.encode(socketData); - socket.sink.add(jsonData); + var voteValue = sliderValue * 10000; + var user = data.username; + if (user == null) return; + if (widget.accessToken != null) { + // TO-DO: Call Acela-Core upvote API using access token. + } else { + try { + const platform = MethodChannel('com.example.acela/auth'); + final String result = await platform.invokeMethod('voteContent', { + 'user': user, + 'author': widget.author, + 'permlink': widget.permlink, + 'weight': voteValue, + 'postingKey': data.postingKey ?? '', + 'hasKey': data.keychainData?.hasId ?? '', + 'hasAuthKey': data.keychainData?.hasAuthKey ?? '', + }); + var response = LoginBridgeResponse.fromJsonString(result); + if (response.valid && response.error.isEmpty) { + if (response.error == "" && + response.data != null && + response.data!.isNotEmpty && + data.keychainData?.hasAuthKey != null) { + var socketData = { + "cmd": "sign_req", + "account": data.username!, + "token": data.keychainData!.hasId, + "data": response.data!, + }; + loadingQR = true; + var jsonData = json.encode(socketData); + socket.sink.add(jsonData); + } else { + Future.delayed(const Duration(seconds: 6), () { + if (mounted) { + setState(() { + isUpVoting = false; + widget.onDone(); + Navigator.of(context).pop(); + }); + } + }); + } } else { - Future.delayed(const Duration(seconds: 6), () { - if (mounted) { - setState(() { - isUpVoting = false; - widget.onDone(); - Navigator.of(context).pop(); - }); - } - }); + if (isUpVoting && mounted) { + setState(() { + isUpVoting = false; + }); + } + showError('Something went wrong.\n${response.error}'); } - } else { - if(isUpVoting && mounted){ + } catch (e) { + if (isUpVoting && mounted) { setState(() { isUpVoting = false; }); } - showError('Something went wrong.\n${response.error}'); + showError('Something went wrong.\n${e.toString()}'); } - } catch (e) { - if(isUpVoting && mounted){ - setState(() { - isUpVoting = false; - }); - } - showError('Something went wrong.\n${e.toString()}'); } } @@ -405,8 +411,14 @@ class _HiveUpvoteDialogState extends State { automaticallyImplyLeading: false, title: ListTile( contentPadding: EdgeInsets.zero, - leading:UserProfileImage(userName: widget.author,), - title: Text("Upvote",style: TextStyle(color: Colors.white,fontWeight: FontWeight.w500),), + leading: UserProfileImage( + userName: widget.author, + ), + title: Text( + "Upvote", + style: + TextStyle(color: Colors.white, fontWeight: FontWeight.w500), + ), subtitle: Text( "@${widget.author}/${widget.permlink}", maxLines: 1, @@ -416,7 +428,10 @@ class _HiveUpvoteDialogState extends State { actions: [ IconButton( splashRadius: 30, - icon: const Icon(Icons.cancel,size: 28,), + icon: const Icon( + Icons.cancel, + size: 28, + ), onPressed: () { widget.onClose(); Navigator.of(context).pop(); diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index d66ed25e..9568e1dd 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -219,7 +219,7 @@ class Communicator { } return memo.decrypted.replaceFirst("#", ''); } - +/* OLD APIs Future getValidCookie(HiveUserData user) async { var uri = '${Communicator.tsServer}/mobile/login?username=${user.username}'; if (user.keychainData != null && user.postingKey == null) { @@ -450,6 +450,7 @@ class Communicator { } } + */ Future> loadAnyFeed(Uri uri) async { var request = http.Request('GET', uri); http.StreamedResponse response = await request.send(); @@ -525,7 +526,7 @@ class Communicator { throw error; } } - +/* OLD APIS. Use Acela-core now. Future> loadVideos(HiveUserData user) async { log("Starting fetch videos ${DateTime.now().toIso8601String()}"); var cookie = await getValidCookie(user); @@ -709,10 +710,10 @@ class Communicator { rethrow; } } - +*/ Future login(String userName, String postingKey) async { var headers = { - 'Accept': 'application/json, text/plain, */*', + 'Accept': 'application/json, text/plain', 'Content-Type': 'application/json' }; diff --git a/lib/src/widgets/story_player.dart b/lib/src/widgets/story_player.dart index 6b49775b..9d7b037b 100644 --- a/lib/src/widgets/story_player.dart +++ b/lib/src/widgets/story_player.dart @@ -255,6 +255,7 @@ class _StoryPlayerState extends State { username: widget.data.username ?? "", hasKey: widget.data.keychainData?.hasId ?? "", hasAuthKey: widget.data.keychainData?.hasAuthKey ?? "", + accessToken: widget.data.accessToken, activeVotes: postInfo!.activeVotes, onClose: () {}, onDone: () { diff --git a/lib/src/widgets/upvote_button.dart b/lib/src/widgets/upvote_button.dart index 8412356c..3f2b8ff2 100644 --- a/lib/src/widgets/upvote_button.dart +++ b/lib/src/widgets/upvote_button.dart @@ -87,6 +87,7 @@ class _UpvoteButtonState extends State { username: widget.appData.username ?? "", hasKey: widget.appData.keychainData?.hasId ?? "", hasAuthKey: widget.appData.keychainData?.hasAuthKey ?? "", + accessToken: widget.appData.accessToken, activeVotes: [], onClose: () {}, onDone: () { From 481608f887feff3f63868d0eb9f612738e5d210b Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 9 Feb 2024 23:11:19 +0530 Subject: [PATCH 364/466] new acela core integration --- .../home_screen/video_upload_sheet.dart | 2 +- lib/src/screens/login/ha_login_screen.dart | 11 +++++----- .../account_settings_screen.dart | 5 ++++- .../screens/my_account/my_account_screen.dart | 6 ++++++ .../update_thumb/update_thumb_screen.dart | 2 ++ .../update_video/video_details_info.dart | 6 ++++++ lib/src/screens/settings/settings_screen.dart | 14 +++++++------ .../upload/new_video_upload_screen.dart | 2 ++ .../upload/podcast/audio_details_info.dart | 4 ++++ .../upload/video/mixins/video_save_mixin.dart | 19 +++++++++--------- .../video/mixins/video_upload_mixin.dart | 20 +++++++++---------- .../upload/video/video_upload_screen.dart | 3 ++- .../comment/comment_action_menu.dart | 1 + .../new_video_details_screen.dart | 1 + .../video_details_screen.dart | 1 + 15 files changed, 64 insertions(+), 33 deletions(-) diff --git a/lib/src/screens/home_screen/video_upload_sheet.dart b/lib/src/screens/home_screen/video_upload_sheet.dart index e438642f..ebb97ce8 100644 --- a/lib/src/screens/home_screen/video_upload_sheet.dart +++ b/lib/src/screens/home_screen/video_upload_sheet.dart @@ -101,7 +101,7 @@ class VideoUploadSheet { username: null, postingKey: null, keychainData: null, - cookie: null, + accessToken: null, resolution: resolution, rpc: rpc, union: union, diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index 9f114ba9..2206c626 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -373,7 +373,7 @@ class _HiveAuthLoginScreenState extends State username: usernameController.text, postingKey: postingKey, keychainData: null, - cookie: null, + accessToken: null, resolution: resolution, rpc: rpc, union: union, @@ -381,8 +381,9 @@ class _HiveAuthLoginScreenState extends State language: lang, ); server.updateHiveUserData(data); - var cookie = await Communicator().getValidCookie(data); - log(cookie); + // TO-DO: get accessToken here + // var cookie = await Communicator().getValidCookie(data); + // log(cookie); Navigator.of(context).pop(); var screen = GQLFeedScreen( appData: data, @@ -425,7 +426,7 @@ class _HiveAuthLoginScreenState extends State username: null, postingKey: null, keychainData: null, - cookie: null, + accessToken: null, resolution: '480p', rpc: 'api.hive.blog', union: GQLCommunicator.defaultGQLServer, @@ -497,7 +498,7 @@ class _HiveAuthLoginScreenState extends State hasExpiry: tokenData[1], hasId: tokenData[0], ), - cookie: null, + accessToken: null, resolution: data.resolution, rpc: data.rpc, union: data.union, diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index 89548832..dc5a8163 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -38,7 +38,7 @@ class _AccountSettingsScreenState extends State { username: null, postingKey: null, keychainData: null, - cookie: null, + accessToken: null, resolution: resolution, rpc: rpc, union: union, @@ -106,6 +106,8 @@ class _AccountSettingsScreenState extends State { onDelete: () async { Navigator.pop(context); try { + /* + // TO-DO: New Acela Core APIs setState(() { isLoading = true; }); @@ -120,6 +122,7 @@ class _AccountSettingsScreenState extends State { setState(() { isLoading = false; }); + */ } catch (e) { setState(() { isLoading = false; diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 8fc4bc2c..6518433d 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -36,9 +36,11 @@ class _MyAccountScreenState extends State @override void initState() { super.initState(); + /* TO-DO: Acela Core integration setState(() { loadVideos = Communicator().loadVideos(widget.data); }); + */ _tabController = TabController(length: 3, vsync: this); _tabController.addListener(() { setState(() { @@ -91,9 +93,11 @@ class _MyAccountScreenState extends State actions: [ IconButton( onPressed: () { + /* TO-DO: Acela Core Integration setState(() { loadVideos = Communicator().loadVideos(widget.data); }); + */ }, icon: Icon(Icons.refresh), ), @@ -200,6 +204,7 @@ class _MyAccountScreenState extends State BottomSheetAction( title: Text('Delete Video'), onPressed: (context) async { + /* TO-DO: Acela Core API Integration Navigator.of(context).pop(); showSnackBar('Deleting...', seconds: 60); bool result = @@ -212,6 +217,7 @@ class _MyAccountScreenState extends State } else { showSnackBar("Something went wrong"); } + */ }, ), ); diff --git a/lib/src/screens/my_account/update_thumb/update_thumb_screen.dart b/lib/src/screens/my_account/update_thumb/update_thumb_screen.dart index 1eee5761..31bdfe7c 100644 --- a/lib/src/screens/my_account/update_thumb/update_thumb_screen.dart +++ b/lib/src/screens/my_account/update_thumb/update_thumb_screen.dart @@ -67,6 +67,7 @@ class _UpdateThumbScreenState extends State { } void completeVideo(HiveUserData user) async { + /* TO-DO: New Acela Core APIs setState(() { isCompleting = true; processText = 'Updating video info'; @@ -86,6 +87,7 @@ class _UpdateThumbScreenState extends State { processText = ''; }); } + */ } Widget _thumbnailPicker(HiveUserData user) { diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index 2adcb690..b8b86284 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -177,6 +177,7 @@ class _VideoDetailsInfoState extends State { 'Please wait. Video is posted on Hive but needs to be marked as published.'); Future.delayed(const Duration(seconds: 6), () async { if (mounted) { + /* TO-DO: Acela Core integration try { await Communicator() .updatePublishState(widget.appData, widget.item.id); @@ -196,6 +197,7 @@ class _VideoDetailsInfoState extends State { 'Video is posted on Hive but needs to be marked as published. Please hit Save button again after few seconds.'); }); } + */ } }); break; @@ -280,6 +282,7 @@ class _VideoDetailsInfoState extends State { var doesPostNotExist = await Communicator() .doesPostNotExist(widget.item.owner, widget.item.permlink, user.rpc); if (doesPostNotExist != true) { + /* TO-DO: Acela-Core integration await Communicator().updatePublishState(user, widget.item.id); setState(() { isCompleting = false; @@ -287,7 +290,9 @@ class _VideoDetailsInfoState extends State { showMessage('Your video was already published.'); showMyDialog(); }); + */ } else { + /* TO-DO: Acela-Core integration var v = await Communicator().updateInfo( user: user, videoId: widget.item.id, @@ -385,6 +390,7 @@ class _VideoDetailsInfoState extends State { } else { throw bridgeResponse.error; } + */ } } catch (e) { showError(e.toString()); diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index eef05074..4a4098af 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -92,7 +92,7 @@ class _SettingsScreenState extends State { String? hasId = await storage.read(key: 'hasId'); String? hasExpiry = await storage.read(key: 'hasExpiry'); String? hasAuthKey = await storage.read(key: 'hasAuthKey'); - String? cookie = await storage.read(key: 'cookie'); + String? accessToken = await storage.read(key: 'accessToken'); String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; String union = await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; @@ -101,7 +101,7 @@ class _SettingsScreenState extends State { HiveUserData( username: username, postingKey: postingKey, - cookie: cookie, + accessToken: accessToken, resolution: optionName, rpc: rpc, union: union, @@ -173,7 +173,7 @@ class _SettingsScreenState extends State { HiveUserData( username: appData.username, postingKey: appData.postingKey, - cookie: appData.cookie, + accessToken: appData.accessToken, resolution: appData.resolution, rpc: appData.rpc, union: appData.union, @@ -258,7 +258,7 @@ class _SettingsScreenState extends State { username: null, postingKey: null, keychainData: null, - cookie: null, + accessToken: null, resolution: resolution, rpc: rpc, union: union, @@ -306,6 +306,7 @@ class _SettingsScreenState extends State { builder: (context) { return DeleteDialog( onDelete: () async { + /* TO-DO: Acela Core integration Navigator.pop(context); try { setState(() { @@ -327,6 +328,7 @@ class _SettingsScreenState extends State { }); showError("Sorry, Something went wrong."); } + */ }, ); }, @@ -443,7 +445,7 @@ class _SettingsScreenState extends State { username: user.username, postingKey: user.postingKey, keychainData: user.keychainData, - cookie: user.cookie, + accessToken: user.accessToken, resolution: user.resolution, union: user.union, rpc: serverUrl, @@ -516,7 +518,7 @@ class _SettingsScreenState extends State { username: user.username, postingKey: user.postingKey, keychainData: user.keychainData, - cookie: user.cookie, + accessToken: user.accessToken, resolution: user.resolution, union: serverUrl, rpc: user.rpc, diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index fbf6b418..c1374efc 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -255,6 +255,7 @@ class _NewVideoUploadScreenState extends State { setState(() { didStartMoveToQueue = true; }); + /* TO-DO: new video upload var videoUploadInfo = await Communicator().uploadInfo( user: user!, thumbnail: thumbName, @@ -277,6 +278,7 @@ class _NewVideoUploadScreenState extends State { showMessage('Video is uploaded & moved to encoding queue'); showMyDialog(item); }); + */ // Step 6. Move Video to Queue } else { throw 'User cancelled the video picker'; diff --git a/lib/src/screens/upload/podcast/audio_details_info.dart b/lib/src/screens/upload/podcast/audio_details_info.dart index 93b23abe..a28465ba 100644 --- a/lib/src/screens/upload/podcast/audio_details_info.dart +++ b/lib/src/screens/upload/podcast/audio_details_info.dart @@ -167,6 +167,7 @@ class _AudioDetailsInfoScreenState extends State { }); try { final String ipfsUrl = IpfsNodeProvider().nodeUrl; + /* TO-DO: Acela Core Integration var podcastResponse = await Communicator().uploadPodcast( user: user, size: widget.size, @@ -265,6 +266,7 @@ class _AudioDetailsInfoScreenState extends State { } else { throw bridgeResponse.error; } + */ } catch (e) { showError(e.toString()); setState(() { @@ -360,6 +362,7 @@ class _AudioDetailsInfoScreenState extends State { }); showMessage( 'Please wait. Podcast is posted on Hive but needs to be marked as published.'); + /* TO-DO: Acela Core Integration Future.delayed(const Duration(seconds: 6), () async { if (mounted) { try { @@ -384,6 +387,7 @@ class _AudioDetailsInfoScreenState extends State { } } }); + */ break; case "sign_nack": setState(() { diff --git a/lib/src/screens/upload/video/mixins/video_save_mixin.dart b/lib/src/screens/upload/video/mixins/video_save_mixin.dart index 19067438..c38b71c5 100644 --- a/lib/src/screens/upload/video/mixins/video_save_mixin.dart +++ b/lib/src/screens/upload/video/mixins/video_save_mixin.dart @@ -26,15 +26,16 @@ class VideoSaveMixin { }) async { try { isSaving.value = true; - await Communicator().updateInfo( - user: user, - videoId: item.id, - title: title, - description: description, - isNsfwContent: isNsfwContent, - tags: tags, - thumbnail: thumbIpfs.isEmpty ? null : thumbIpfs, - communityID: communityId); + // TO-DO: Update here + // await Communicator().updateInfo( + // user: user, + // videoId: item.id, + // title: title, + // description: description, + // isNsfwContent: isNsfwContent, + // tags: tags, + // thumbnail: thumbIpfs.isEmpty ? null : thumbIpfs, + // communityID: communityId); isSaving.value = false; successDialog(); } catch (e) { diff --git a/lib/src/screens/upload/video/mixins/video_upload_mixin.dart b/lib/src/screens/upload/video/mixins/video_upload_mixin.dart index c6c5bebb..b67f8906 100644 --- a/lib/src/screens/upload/video/mixins/video_upload_mixin.dart +++ b/lib/src/screens/upload/video/mixins/video_upload_mixin.dart @@ -35,19 +35,19 @@ mixin Upload { log('upload started'); int fileSize = _checkFileSize(size); var path = pickedVideoFile.path; - var videoUploadReponse = await _uploadToServer(path, videoUploadProgress); - var name = videoUploadReponse.name; + // var videoUploadReponse = await _uploadToServer(path, videoUploadProgress); + // var name = videoUploadReponse.name; _initiateNextUpload(); var thumbPath = await _getThumbnail(path); _initiateNextUpload(); - var thumbReponse = await uploadThumbnail(thumbPath); + // var thumbReponse = await uploadThumbnail(thumbPath); _initiateNextUpload(); - log('Uploaded file name is $name'); - log('Uploaded thumbnail file name is ${thumbReponse.name}'); - uploadedVideoItem= await _encodeAndUploadInfo(path, - hiveUserData, thumbReponse.name, originalFileName, fileSize, name); - uploadStatus.value = UploadStatus.ended; + // log('Uploaded file name is $name'); + // log('Uploaded thumbnail file name is ${thumbReponse.name}'); + // uploadedVideoItem= await _encodeAndUploadInfo(path, + // hiveUserData, thumbReponse.name, originalFileName, fileSize, name); + // uploadStatus.value = UploadStatus.ended; _initiateNextUpload(); } @@ -99,7 +99,7 @@ mixin Upload { } return fileSize; } - +/* TO-DO: This with acela Core Future uploadThumbnail(String path) async { thumbnailUploadStatus.value = UploadStatus.started; var thumbReponse = await _uploadToServer(path, thumbnailUploadProgress); @@ -157,5 +157,5 @@ mixin Upload { ); return UploadResponse(name: name, url: url); } - + */ } diff --git a/lib/src/screens/upload/video/video_upload_screen.dart b/lib/src/screens/upload/video/video_upload_screen.dart index 89691264..7de9d791 100644 --- a/lib/src/screens/upload/video/video_upload_screen.dart +++ b/lib/src/screens/upload/video/video_upload_screen.dart @@ -155,7 +155,8 @@ class _VideoUploadScreenState extends State { thumbnailUploadProgress: controller.thumbnailUploadProgress, thumbnailUploadRespone: controller.thumbnailUploadResponse, onUploadFile: (file) { - controller.uploadThumbnail(file.path); + // TO-DO: upload thumbnail + // controller.uploadThumbnail(file.path); }, ); } diff --git a/lib/src/screens/video_details_screen/comment/comment_action_menu.dart b/lib/src/screens/video_details_screen/comment/comment_action_menu.dart index ada1076a..4179c3fa 100644 --- a/lib/src/screens/video_details_screen/comment/comment_action_menu.dart +++ b/lib/src/screens/video_details_screen/comment/comment_action_menu.dart @@ -58,6 +58,7 @@ class CommentActionMenu extends StatelessWidget { author: author, permlink: permlink, username: appData.username ?? "", + accessToken: appData.accessToken, hasKey: appData.keychainData?.hasId ?? "", hasAuthKey: appData.keychainData?.hasAuthKey ?? "", activeVotes: [], diff --git a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart index 7e665428..45637e3d 100644 --- a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart +++ b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart @@ -476,6 +476,7 @@ class _NewVideoDetailsScreenState extends State { author: widget.item.author?.username ?? 'sagarkothari88', permlink: widget.item.permlink ?? 'ctbtwcxbbd', username: widget.appData.username ?? "", + accessToken: widget.appData.accessToken, hasKey: widget.appData.keychainData?.hasId ?? "", hasAuthKey: widget.appData.keychainData?.hasAuthKey ?? "", activeVotes: postInfo!.activeVotes, diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 64a06c41..3d6377bf 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -233,6 +233,7 @@ class _VideoDetailsScreenState extends State { author: widget.vm.author, permlink: widget.vm.permlink, username: appData.username ?? "", + accessToken: appData.accessToken, hasKey: appData.keychainData?.hasId ?? "", hasAuthKey: appData.keychainData?.hasAuthKey ?? "", From f4f6499cb596382021dee1dbaff1f71f4f765a1d Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sat, 10 Feb 2024 12:35:53 +0530 Subject: [PATCH 365/466] new login integration --- android/app/src/main/assets/index.html | 134 ++++++++++++- .../kotlin/tv/threespeak/app/MainActivity.kt | 12 ++ ios/Runner/AcelaWebViewController.swift | 13 ++ ios/Runner/Bridges/Auth/HASBridge.swift | 12 ++ ios/Runner/public/index.html | 132 +++++++++++++ lib/main.dart | 1 - .../community_details_screen.dart | 2 - .../widgets/home_feed_video_slider.dart | 1 - .../widgets/tab_title_toast.dart | 1 - .../screens/home_screen/new_home_screen.dart | 5 - .../home_screen/video_upload_sheet.dart | 1 - lib/src/screens/login/ha_login_screen.dart | 180 +++++++++++++----- .../account_settings_screen.dart | 3 - .../screens/my_account/my_account_screen.dart | 2 - .../update_video/video_details_info.dart | 4 - lib/src/screens/my_account/video_preview.dart | 1 - .../screens/podcast/view/podcast_search.dart | 2 - .../new_pod_cast_epidose_player.dart | 3 - lib/src/screens/settings/settings_screen.dart | 2 - lib/src/screens/stories/story_feed_body.dart | 1 - .../upload/podcast/audio_details_info.dart | 1 - .../upload/video/mixins/video_save_mixin.dart | 1 - .../video/mixins/video_upload_mixin.dart | 4 - .../hive_upvote_dialog.dart | 1 - .../video_details_screen.dart | 1 - lib/src/utils/communicator.dart | 75 +++----- lib/src/widgets/fab_overlay.dart | 2 +- lib/src/widgets/gql_feed_list_item.dart | 5 - lib/src/widgets/list_tile_video.dart | 8 +- lib/src/widgets/loading_screen.dart | 4 +- lib/src/widgets/shorts_xlist_item.dart | 9 - lib/src/widgets/story_player.dart | 1 - 32 files changed, 473 insertions(+), 151 deletions(-) diff --git a/android/app/src/main/assets/index.html b/android/app/src/main/assets/index.html index 00b6a0af..c196a60c 100644 --- a/android/app/src/main/assets/index.html +++ b/android/app/src/main/assets/index.html @@ -731,7 +731,7 @@ } } - function getDecryptedChallenge(username, authKey) { + function getDecryptedChallenge(username, authKey, data) { try { const decryptedData = JSON.parse( CryptoJS.AES.decrypt(data, authKey).toString(CryptoJS.enc.Utf8) @@ -753,6 +753,138 @@ } } + function getPostingAuthOps(username, authKey) { + hive.api.getAccounts([username], function (err, result) { + console.log(err, result); + if ( + (err === null || err === undefined) && + result != null && + result != undefined && + Array.isArray(result) && + result.length === 1 + ) { + let account = result[0]; + let doWeHavePostingAuth = false; + if (Array.isArray(account.posting.account_auths)) { + account.posting.account_auths.forEach(function (item) { + if (item[0] === "threespeak") { + doWeHavePostingAuth = true; + } + }); + if (!doWeHavePostingAuth) { + let auths = account.posting.account_auths; + auths.push(["threespeak", 1]); + console.log(`new auths - ${JSON.stringify(auths)}`); + const newPostingAuth = { + weight_threshold: account.posting.weight_threshold, + account_auths: auths, + key_auths: account.posting.key_auths, + }; + const operations = []; + operations.push([ + "account_update", + { + account: username, + owner: undefined, + active: account.active, + posting: newPostingAuth, + memo_key: account.memo_key, + json_metadata: account.json_metadata, + }, + ]); + console.log(`Operations - ${JSON.stringify(operations)}`); + const sign_data = { + key_type: "active", + ops: operations, + broadcast: true, + }; + const data = CryptoJS.AES.encrypt( + JSON.stringify(sign_data), + auth_key + ).toString(); + replyToNative({ + type: "getPostingAuthOps", + valid: true, + username: username, + error: "", + data: data, + }); + } else { + replyToNative({ + type: "getPostingAuthOps", + valid: true, + username: username, + error: "", + data: "", + }); + } + } else { + replyToNative({ + type: "getPostingAuthOps", + valid: false, + username: username, + error: "failed getting account information", + data: "", + }); + } + } else { + replyToNative({ + type: "getPostingAuthOps", + valid: false, + username: username, + error: "failed getting account information", + data: "", + }); + } + }); + } + + function doWeHavePostingAuth(username) { + hive.api.getAccounts([username], function (err, result) { + console.log(err, result); + if ( + (err === null || err === undefined) && + result != null && + result != undefined && + Array.isArray(result) && + result.length === 1 + ) { + let account = result[0]; + let doWe = false; + if (Array.isArray(account.posting.account_auths)) { + account.posting.account_auths.forEach(function (item) { + if (item[0] === "threespeak") { + doWe = true; + } + }); + replyToNative({ + type: "doWeHavePostingAuth", + valid: true, + username: username, + error: "", + data: doWe ? "true" : "false", + }); + } else { + replyToNative({ + type: "doWeHavePostingAuth", + valid: true, + username: username, + error: "", + data: "false", + }); + } + } else { + replyToNative({ + type: "doWeHavePostingAuth", + valid: false, + username: username, + error: "failed getting account information", + data: "", + }); + } + }); + } + function replyToNative(result) { // window.webkit.messageHandlers.acela.postMessage(result); Android.postMessage(JSON.stringify(result)); diff --git a/android/app/src/main/kotlin/tv/threespeak/app/MainActivity.kt b/android/app/src/main/kotlin/tv/threespeak/app/MainActivity.kt index b72ed8b4..d9f06109 100644 --- a/android/app/src/main/kotlin/tv/threespeak/app/MainActivity.kt +++ b/android/app/src/main/kotlin/tv/threespeak/app/MainActivity.kt @@ -45,6 +45,10 @@ class MainActivity : AudioServiceActivity() { webView?.evaluateJavascript("getDecryptedHASToken('$username','$authKey','$data');", null) } else if (call.method == "getEncryptedChallenge" && username != null && authKey != null) { webView?.evaluateJavascript("getEncryptedChallenge('$username','$authKey');", null) + } else if (call.method == "getDecryptedChallenge" && username != null && authKey != null && data != null) { + webView?.evaluateJavascript("getDecryptedChallenge('$username','$authKey', '$data');", null) + } else if (call.method == "doWeHavePostingAuth" && username != null) { + webView?.evaluateJavascript("doWeHavePostingAuth('$username');", null) } } MethodChannel( @@ -222,6 +226,12 @@ class WebAppInterface(private val mContext: Context) { JSBridgeAction.GET_ENCRYPTED_CHALLENGE.value -> { main.result?.success(message) } + JSBridgeAction.GET_DECRYPTED_CHALLENGE.value -> { + main.result?.success(message) + } + JSBridgeAction.DO_WE_HAVE_POSTING_AUTH.value -> { + main.result?.success(message) + } } } } @@ -242,4 +252,6 @@ enum class JSBridgeAction(val value: String) { POST_AUDIO("postAudio"), GET_PROOF_PAYLOAD("getProofOfPayload"), GET_ENCRYPTED_CHALLENGE("getEncryptedChallenge"), + GET_DECRYPTED_CHALLENGE("getDecryptedChallenge"), + DO_WE_HAVE_POSTING_AUTH("doWeHavePostingAuth"), } diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index ef9e94fb..b5c855ce 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -29,6 +29,7 @@ class AcelaWebViewController: UIViewController { var getProofOfPayloadHandler: ((String) -> Void)? = nil var getEncryptedChallengeHandler: ((String) -> Void)? = nil var getDecryptedChallengeHandler: ((String) -> Void)? = nil + var doWeHavePostingAuthHandler: ((String) -> Void)? = nil override func viewDidLoad() { super.viewDidLoad() @@ -160,6 +161,13 @@ class AcelaWebViewController: UIViewController { } } + func doWeHavePostingAuth(username: String, handler: @escaping (String) -> Void) { + doWeHavePostingAuthHandler = handler + OperationQueue.main.addOperation { + self.webView?.evaluateJavaScript("doWeHavePostingAuth('\(username)');") + } + } + func postPodcast( thumbnail: String, enclosureUrl: String, @@ -311,6 +319,11 @@ extension AcelaWebViewController: WKScriptMessageHandler { let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) else { return } getDecryptedChallengeHandler?(response) + case "doWeHavePostingAuth": + guard + let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) + else { return } + doWeHavePostingAuthHandler?(response) default: debugPrint("Do nothing here.") } } diff --git a/ios/Runner/Bridges/Auth/HASBridge.swift b/ios/Runner/Bridges/Auth/HASBridge.swift index a0cd8609..fb1db024 100644 --- a/ios/Runner/Bridges/Auth/HASBridge.swift +++ b/ios/Runner/Bridges/Auth/HASBridge.swift @@ -87,6 +87,18 @@ class HASBridge { acela.getDecryptedChallenge(username: username, authKey: authKey, data: data) { data in result(data) } + case "doWeHavePostingAuth": + guard + let arguments = call.arguments as? NSDictionary, + let username = arguments ["username"] as? String, + let acela = acela + else { + result(FlutterMethodNotImplemented) + return + } + acela.doWeHavePostingAuth(username: username) { data in + result(data) + } default: result(FlutterMethodNotImplemented) } diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index b6db98ab..c2f62063 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -753,6 +753,138 @@ } } + function getPostingAuthOps(username, authKey) { + hive.api.getAccounts([username], function (err, result) { + console.log(err, result); + if ( + (err === null || err === undefined) && + result != null && + result != undefined && + Array.isArray(result) && + result.length === 1 + ) { + let account = result[0]; + let doWeHavePostingAuth = false; + if (Array.isArray(account.posting.account_auths)) { + account.posting.account_auths.forEach(function (item) { + if (item[0] === "threespeak") { + doWeHavePostingAuth = true; + } + }); + if (!doWeHavePostingAuth) { + let auths = account.posting.account_auths; + auths.push(["threespeak", 1]); + console.log(`new auths - ${JSON.stringify(auths)}`); + const newPostingAuth = { + weight_threshold: account.posting.weight_threshold, + account_auths: auths, + key_auths: account.posting.key_auths, + }; + const operations = []; + operations.push([ + "account_update", + { + account: username, + owner: undefined, + active: account.active, + posting: newPostingAuth, + memo_key: account.memo_key, + json_metadata: account.json_metadata, + }, + ]); + console.log(`Operations - ${JSON.stringify(operations)}`); + const sign_data = { + key_type: "active", + ops: operations, + broadcast: true, + }; + const data = CryptoJS.AES.encrypt( + JSON.stringify(sign_data), + auth_key + ).toString(); + replyToNative({ + type: "getPostingAuthOps", + valid: true, + username: username, + error: "", + data: data, + }); + } else { + replyToNative({ + type: "getPostingAuthOps", + valid: true, + username: username, + error: "", + data: "", + }); + } + } else { + replyToNative({ + type: "getPostingAuthOps", + valid: false, + username: username, + error: "failed getting account information", + data: "", + }); + } + } else { + replyToNative({ + type: "getPostingAuthOps", + valid: false, + username: username, + error: "failed getting account information", + data: "", + }); + } + }); + } + + function doWeHavePostingAuth(username) { + hive.api.getAccounts([username], function (err, result) { + console.log(err, result); + if ( + (err === null || err === undefined) && + result != null && + result != undefined && + Array.isArray(result) && + result.length === 1 + ) { + let account = result[0]; + let doWe = false; + if (Array.isArray(account.posting.account_auths)) { + account.posting.account_auths.forEach(function (item) { + if (item[0] === "threespeak") { + doWe = true; + } + }); + replyToNative({ + type: "doWeHavePostingAuth", + valid: true, + username: username, + error: "", + data: doWe ? "true" : "false", + }); + } else { + replyToNative({ + type: "doWeHavePostingAuth", + valid: true, + username: username, + error: "", + data: "false", + }); + } + } else { + replyToNative({ + type: "doWeHavePostingAuth", + valid: false, + username: username, + error: "failed getting account information", + data: "", + }); + } + }); + } + function replyToNative(result) { window.webkit.messageHandlers.acela.postMessage(result); // Android.postMessage(JSON.stringify(result)); diff --git a/lib/main.dart b/lib/main.dart index 737e6dc2..160a349e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,5 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/image_resolution_provider.dart'; -import 'package:acela/src/global_provider/ipfs_node_provider.dart'; import 'package:acela/src/global_provider/video_setting_provider.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/new_home_screen.dart'; diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index b2c926ae..c41ebb7a 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -12,7 +12,6 @@ import 'package:acela/src/screens/video_details_screen/video_details_screen.dart import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; -import 'package:acela/src/widgets/list_tile_video.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/retry.dart'; import 'package:flutter/material.dart'; @@ -20,7 +19,6 @@ import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:http/http.dart'; import 'package:http/http.dart' as http; import 'package:provider/provider.dart'; -import 'package:timeago/timeago.dart' as timeago; import 'package:url_launcher/url_launcher.dart'; class CommunityDetailScreen extends StatefulWidget { diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_slider.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_slider.dart index 48681f74..9ecc1253 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_slider.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_slider.dart @@ -1,7 +1,6 @@ import 'package:acela/src/screens/home_screen/home_screen_feed_item/controller/home_feed_video_controller.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:better_player/better_player.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/tab_title_toast.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/tab_title_toast.dart index cbb67e8f..26f537dc 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/tab_title_toast.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/tab_title_toast.dart @@ -1,4 +1,3 @@ -import 'dart:developer'; import 'package:flutter/material.dart'; diff --git a/lib/src/screens/home_screen/new_home_screen.dart b/lib/src/screens/home_screen/new_home_screen.dart index 698c20bc..2ef80a09 100644 --- a/lib/src/screens/home_screen/new_home_screen.dart +++ b/lib/src/screens/home_screen/new_home_screen.dart @@ -1,6 +1,4 @@ -import 'dart:developer'; -import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/about/about_home_screen.dart'; import 'package:acela/src/screens/communities_screen/communities_screen.dart'; @@ -15,16 +13,13 @@ import 'package:acela/src/screens/search/search_screen.dart'; import 'package:acela/src/screens/settings/settings_screen.dart'; import 'package:acela/src/screens/stories/new_tab_based_stories.dart'; import 'package:acela/src/screens/trending_tags/trending_tags.dart'; -import 'package:acela/src/screens/upload/new_video_upload_screen.dart'; import 'package:acela/src/screens/upload/podcast/podcast_upload_screen.dart'; import 'package:acela/src/screens/upload/video/controller/video_upload_controller.dart'; import 'package:acela/src/screens/upload/video/video_upload_screen.dart'; -import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:acela/src/widgets/fab_custom.dart'; import 'package:acela/src/widgets/fab_overlay.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:provider/provider.dart'; import 'package:upgrader/upgrader.dart'; diff --git a/lib/src/screens/home_screen/video_upload_sheet.dart b/lib/src/screens/home_screen/video_upload_sheet.dart index ebb97ce8..a2323a6d 100644 --- a/lib/src/screens/home_screen/video_upload_sheet.dart +++ b/lib/src/screens/home_screen/video_upload_sheet.dart @@ -2,7 +2,6 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/screens/upload/new_video_upload_screen.dart'; import 'package:acela/src/screens/upload/video/video_upload_screen.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index 2206c626..c860f4da 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/models/action_response.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/new_home_screen.dart'; @@ -35,7 +36,9 @@ class _HiveAuthLoginScreenState extends State var usernameController = TextEditingController(); late WebSocketChannel socket; String authKey = ''; + String hasIdToken = ''; String proofOfPayload = ''; + String signedHash = ''; String? qrCode; var loadingQR = false; var timer = 0; @@ -109,6 +112,7 @@ class _HiveAuthLoginScreenState extends State qrCode = null; timer = 0; loadingQR = false; + hasIdToken = ''; }); break; case "challenge_ack": @@ -116,14 +120,20 @@ class _HiveAuthLoginScreenState extends State decryptChallenge(widget.appData, messageData); break; case "challenge_nack": - showError("You denied signing the auth"); + showError("You denied signing the auth for authentication"); setState(() { proofOfPayload = ''; + signedHash = ''; qrCode = null; timer = 0; loadingQR = false; }); break; + case "sign_ack": + break; + case "sign_nack": + showError("You denied granting posting authority to 3Speak"); + break; default: log('Default case here'); } @@ -354,50 +364,94 @@ class _HiveAuthLoginScreenState extends State }); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); if (bridgeResponse.valid) { - var response = - await Communicator().login(usernameController.text, postingKey); - if (response.valid) { - debugPrint("Successful login"); - String resolution = await storage.read(key: 'resolution') ?? '480p'; - String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - String union = await storage.read(key: 'union') ?? - GQLCommunicator.defaultGQLServer; - String? lang = await storage.read(key: 'lang'); - await storage.write(key: 'username', value: usernameController.text); - await storage.write(key: 'postingKey', value: postingKey); - await storage.delete(key: 'hasId'); - await storage.delete(key: 'hasExpiry'); - await storage.delete(key: 'hasAuthKey'); - await storage.delete(key: 'cookie'); - var data = HiveUserData( - username: usernameController.text, - postingKey: postingKey, - keychainData: null, - accessToken: null, - resolution: resolution, - rpc: rpc, - union: union, - loaded: true, - language: lang, - ); - server.updateHiveUserData(data); - // TO-DO: get accessToken here - // var cookie = await Communicator().getValidCookie(data); - // log(cookie); - Navigator.of(context).pop(); - var screen = GQLFeedScreen( - appData: data, - username: usernameController.text, - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).pushReplacement(route); - showMessage( - 'You have successfully logged in as - ${usernameController.text}'); - setState(() { - isLoading = false; - }); + final String doWeHave = + await MethodChannel("blog.hive.auth/bridge").invokeMethod( + 'doWeHavePostingAuth', + { + 'username': usernameController.text, + }, + ); + var doWeHaveResponse = LoginBridgeResponse.fromJsonString(doWeHave); + if (doWeHaveResponse.valid) { + if (doWeHaveResponse.data != null && + doWeHaveResponse.data == "true") { + // we have posting authority. we can login now. + String proofPayload = json.encode({ + 'account': usernameController.text, + 'ts': DateTime.now().toIso8601String() + }); + const platform = MethodChannel('com.example.acela/auth'); + final String result = + await platform.invokeMethod('getProofOfPayload', { + 'username': usernameController.text, + 'postingKey': postingKey, + 'proof': proofPayload, + }); + LoginBridgeResponse actionResponse = LoginBridgeResponse.fromJsonString(result); + if (actionResponse.valid && + actionResponse.error == '' && + actionResponse.data != null && actionResponse.data!.isNotEmpty) { + var loginApiResponse = await Communicator().login( + usernameController.text, proofPayload, actionResponse.data!); + if (loginApiResponse.valid) { + debugPrint("Successful login"); + String resolution = + await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + String union = await storage.read(key: 'union') ?? + GQLCommunicator.defaultGQLServer; + String? lang = await storage.read(key: 'lang'); + await storage.write( + key: 'username', value: usernameController.text); + await storage.write(key: 'postingKey', value: postingKey); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); + await storage.delete(key: 'cookie'); + var data = HiveUserData( + username: usernameController.text, + postingKey: postingKey, + keychainData: null, + accessToken: loginApiResponse.data, + resolution: resolution, + rpc: rpc, + union: union, + loaded: true, + language: lang, + ); + server.updateHiveUserData(data); + Navigator.of(context).pop(); + var screen = GQLFeedScreen( + appData: data, + username: usernameController.text, + ); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).pushReplacement(route); + showMessage( + 'You have successfully logged in as - ${usernameController.text}'); + setState(() { + isLoading = false; + }); + } else { + showError(loginApiResponse.error); + setState(() { + isLoading = false; + }); + } + } else { + showError(actionResponse.error); + setState(() { + isLoading = false; + }); + } + } else { + showError(doWeHaveResponse.error); + setState(() { + isLoading = false; + }); + } } else { - showError(response.error); + showError(doWeHaveResponse.error); setState(() { isLoading = false; }); @@ -459,14 +513,49 @@ class _HiveAuthLoginScreenState extends State var proof = bridgeResponse.data; var payload = proofOfPayload; setState(() { - proofOfPayload = ''; + signedHash = bridgeResponse.data!; }); + final String postingAuthResponse = + await platform.invokeMethod('getPostingAuthOps', { + 'username': usernameController.text, + 'authKey': authKey, + }); + var postingAuthBridgeResponse = + LoginBridgeResponse.fromJsonString(postingAuthResponse); + if (postingAuthBridgeResponse.valid) { + if (postingAuthBridgeResponse.data != null && + postingAuthBridgeResponse.data!.isNotEmpty) { + // get posting authority here. + var socketData = { + "cmd": "sign_req", + "account": usernameController.text, + "token": hasIdToken, + "data": bridgeResponse.data!, + }; + var jsonEncodedData = json.encode(socketData); + socket.sink.add(jsonEncodedData); + } else { + // Posting Auth Data empty = we already have posting authority + // execute acela core login API + performSignInWithAccessTokenHere(); + } + } else { + // error when getting posting authority details. show error to user. + } } else { showMessage( 'Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); } } + void performSignInWithAccessTokenHere() { + debugPrint("Signed proof is $signedHash"); + debugPrint("Proof of Payload is $proofOfPayload"); + debugPrint("Username is ${usernameController.text}"); + // execute another function similar to + // Future login(String userName, String postingKey) async { + } + void decryptData(HiveUserData data, String encryptedData) async { final String response = await platform.invokeMethod('getDecryptedHASToken', { @@ -517,6 +606,7 @@ class _HiveAuthLoginScreenState extends State json.decode(eChallengeResponse)['data'] as String; var eData = eChallengeResponseData.split("|")[0]; setState(() { + hasIdToken = tokenData[0]; proofOfPayload = eChallengeResponseData.split("|")[1]; }); var socketData = { diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index dc5a8163..6532fca1 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -1,11 +1,8 @@ -import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/new_home_screen.dart'; import 'package:acela/src/screens/my_account/account_settings/widgets/delete_dialog.dart'; -import 'package:acela/src/screens/my_account/account_settings/widgets/dialog_button.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 6518433d..f77cb25b 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -2,7 +2,6 @@ import 'dart:developer'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; -import 'package:acela/src/screens/my_account/account_settings/account_settings_screen.dart'; import 'package:acela/src/screens/my_account/update_thumb/update_thumb_screen.dart'; import 'package:acela/src/screens/my_account/update_video/video_primary_info.dart'; import 'package:acela/src/screens/my_account/video_preview.dart'; @@ -10,7 +9,6 @@ import 'package:acela/src/screens/settings/settings_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index b8b86284..9309bf65 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -3,12 +3,9 @@ import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/global_provider/ipfs_node_provider.dart'; -import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/my_account/video_ops.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; -import 'package:acela/src/screens/my_account/my_account_screen.dart'; import 'package:acela/src/screens/my_account/update_video/add_bene_sheet.dart'; import 'package:acela/src/screens/settings/settings_screen.dart'; import 'package:acela/src/utils/communicator.dart'; @@ -16,7 +13,6 @@ import 'package:acela/src/utils/safe_convert.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:image_picker/image_picker.dart'; diff --git a/lib/src/screens/my_account/video_preview.dart b/lib/src/screens/my_account/video_preview.dart index 17ec6baf..d66e5965 100644 --- a/lib/src/screens/my_account/video_preview.dart +++ b/lib/src/screens/my_account/video_preview.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; diff --git a/lib/src/screens/podcast/view/podcast_search.dart b/lib/src/screens/podcast/view/podcast_search.dart index 32271a29..613aac92 100644 --- a/lib/src/screens/podcast/view/podcast_search.dart +++ b/lib/src/screens/podcast/view/podcast_search.dart @@ -2,8 +2,6 @@ import 'dart:async'; import 'package:acela/src/models/podcast/trending_podcast_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/screens/podcast/view/podcast_trending.dart'; -import 'package:acela/src/screens/podcast/view/podcasts_feed.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_feed_item.dart'; import 'package:acela/src/utils/podcast/podcast_communicator.dart'; import 'package:flutter/material.dart'; diff --git a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart index 30e2a8f6..e3d39ae0 100644 --- a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart +++ b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:acela/src/models/podcast/podcast_episode_chapters.dart'; import 'package:acela/src/models/podcast/podcast_episodes.dart'; -import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/podcast/controller/podcast_chapters_controller.dart'; import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; import 'package:acela/src/screens/podcast/widgets/favourite.dart'; @@ -9,12 +8,10 @@ import 'package:acela/src/screens/podcast/widgets/podcast_info_description.dart' import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart'; -import 'package:acela/src/screens/podcast/widgets/value_for_value_view.dart'; import 'package:acela/src/screens/podcast/widgets/audio_player/action_tools.dart'; import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; import 'package:acela/src/widgets/cached_image.dart'; import 'package:audio_service/audio_service.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index 4a4098af..103461ad 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -5,13 +5,11 @@ import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/new_home_screen.dart'; import 'package:acela/src/screens/my_account/account_settings/widgets/delete_dialog.dart'; import 'package:acela/src/screens/settings/add_cutom_union_indexer.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:get_storage/get_storage.dart'; import 'package:provider/provider.dart'; import 'package:upgrader/upgrader.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/lib/src/screens/stories/story_feed_body.dart b/lib/src/screens/stories/story_feed_body.dart index 75d90aa8..d9c2d8dd 100644 --- a/lib/src/screens/stories/story_feed_body.dart +++ b/lib/src/screens/stories/story_feed_body.dart @@ -1,4 +1,3 @@ -import 'dart:ffi'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; diff --git a/lib/src/screens/upload/podcast/audio_details_info.dart b/lib/src/screens/upload/podcast/audio_details_info.dart index a28465ba..a45b97d9 100644 --- a/lib/src/screens/upload/podcast/audio_details_info.dart +++ b/lib/src/screens/upload/podcast/audio_details_info.dart @@ -6,7 +6,6 @@ import 'dart:ui' as ui; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/ipfs_node_provider.dart'; -import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/my_account/video_ops.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/my_account/update_video/add_bene_sheet.dart'; diff --git a/lib/src/screens/upload/video/mixins/video_save_mixin.dart b/lib/src/screens/upload/video/mixins/video_save_mixin.dart index c38b71c5..e13b854e 100644 --- a/lib/src/screens/upload/video/mixins/video_save_mixin.dart +++ b/lib/src/screens/upload/video/mixins/video_save_mixin.dart @@ -2,7 +2,6 @@ import 'package:acela/src/models/my_account/video_ops.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_upload/video_upload_prepare_response.dart'; import 'package:acela/src/screens/settings/settings_screen.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:flutter/cupertino.dart'; class VideoSaveMixin { diff --git a/lib/src/screens/upload/video/mixins/video_upload_mixin.dart b/lib/src/screens/upload/video/mixins/video_upload_mixin.dart index b67f8906..4010bff2 100644 --- a/lib/src/screens/upload/video/mixins/video_upload_mixin.dart +++ b/lib/src/screens/upload/video/mixins/video_upload_mixin.dart @@ -3,13 +3,9 @@ import 'dart:io'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_upload/upload_response.dart'; import 'package:acela/src/models/video_upload/video_upload_prepare_response.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/enum.dart'; -import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; -import 'package:ffmpeg_kit_flutter/media_information_session.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:tus_client/tus_client.dart'; import 'package:video_thumbnail/video_thumbnail.dart'; mixin Upload { diff --git a/lib/src/screens/video_details_screen/hive_upvote_dialog.dart b/lib/src/screens/video_details_screen/hive_upvote_dialog.dart index 4b3559bf..59900083 100644 --- a/lib/src/screens/video_details_screen/hive_upvote_dialog.dart +++ b/lib/src/screens/video_details_screen/hive_upvote_dialog.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; -import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 3d6377bf..34fc4177 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -11,7 +11,6 @@ import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/comment/hive_comment_dialog.dart'; -import 'package:acela/src/screens/video_details_screen/comment/video_details_comments.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 9568e1dd..8a8aeecb 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'dart:developer'; -import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/action_response.dart'; import 'package:acela/src/models/communities_models/request/communities_request_model.dart'; import 'package:acela/src/models/communities_models/response/communities_response_models.dart'; @@ -10,17 +9,11 @@ import 'package:acela/src/models/hive_post_info/hive_user_posting_key.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/login/memo_response.dart'; import 'package:acela/src/models/my_account/video_ops.dart'; -import 'package:acela/src/models/podcast/upload/podcast_episode_upload_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_upload/does_post_exists.dart'; -import 'package:acela/src/models/video_upload/video_upload_complete_request.dart'; -import 'package:acela/src/models/video_upload/video_upload_login_response.dart'; -import 'package:acela/src/models/video_upload/video_upload_prepare_response.dart'; -import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:http/http.dart' as http; import 'package:http/http.dart'; @@ -219,6 +212,7 @@ class Communicator { } return memo.decrypted.replaceFirst("#", ''); } + /* OLD APIs Future getValidCookie(HiveUserData user) async { var uri = '${Communicator.tsServer}/mobile/login?username=${user.username}'; @@ -526,6 +520,7 @@ class Communicator { throw error; } } + /* OLD APIS. Use Acela-core now. Future> loadVideos(HiveUserData user) async { log("Starting fetch videos ${DateTime.now().toIso8601String()}"); @@ -711,52 +706,40 @@ class Communicator { } } */ - Future login(String userName, String postingKey) async { + Future login( + String userName, + String proofOfPayload, + String proof, + ) async { var headers = { 'Accept': 'application/json, text/plain', 'Content-Type': 'application/json' }; - try { - String proofPayload = json.encode( - {'account': userName, 'ts': DateTime.now().toIso8601String()}); - - const platform = MethodChannel('com.example.acela/auth'); - final String result = await platform.invokeMethod('getProofOfPayload', { - 'username': userName, - 'postingKey': postingKey, - 'proof': proofPayload, + var body = json.encode({ + "username": userName, + "network": "hive", + "authority_type": "posting", + "proof_payload": proofOfPayload, + "proof": proof }); - ActionResponse actionResponse = ActionResponse.fromJsonString(result); - if (actionResponse.valid && actionResponse.error == '') { - var body = json.encode({ - "username": userName, - "network": "hive", - "authority_type": "posting", - "proof_payload": proofPayload, - "proof": actionResponse.data - }); - http.Response response = await post( - Uri.parse( - '${Communicator.acelaServer}/api/v1/auth/login_singleton'), - headers: headers, - body: body); - - if (response.statusCode >= 200 && response.statusCode < 300) { - return ActionResponse( - data: json.decode(response.body)['access_token'], - valid: true, - error: ''); - } else if (response.statusCode == 400) { - return ActionResponse( - data: '', - valid: false, - error: json.decode(response.body)['reason']); - } else { - return ActionResponse(data: '', valid: false, error: 'Server Error'); - } + http.Response response = await post( + Uri.parse('${Communicator.acelaServer}/api/v1/auth/login_singleton'), + headers: headers, + body: body); + + if (response.statusCode >= 200 && response.statusCode < 300) { + return ActionResponse( + data: json.decode(response.body)['access_token'], + valid: true, + error: ''); + } else if (response.statusCode == 400) { + return ActionResponse( + data: '', + valid: false, + error: json.decode(response.body)['reason']); } else { - return ActionResponse(data: '', valid: false, error: 'Incorrect Key'); + return ActionResponse(data: '', valid: false, error: 'Server Error'); } } catch (e) { return ActionResponse(data: '', valid: false, error: e.toString()); diff --git a/lib/src/widgets/fab_overlay.dart b/lib/src/widgets/fab_overlay.dart index 1f17a637..0e40d7bf 100644 --- a/lib/src/widgets/fab_overlay.dart +++ b/lib/src/widgets/fab_overlay.dart @@ -50,7 +50,7 @@ class FabOverlay extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(10)), color: Theme .of(context) - .backgroundColor, + .colorScheme.background, ), child: Text(data.displayName), ), diff --git a/lib/src/widgets/gql_feed_list_item.dart b/lib/src/widgets/gql_feed_list_item.dart index 6bde7c0f..b4844835 100644 --- a/lib/src/widgets/gql_feed_list_item.dart +++ b/lib/src/widgets/gql_feed_list_item.dart @@ -1,20 +1,15 @@ -import 'dart:convert'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/video_details_screen/new_video_details_info.dart'; import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; -import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; -import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:timeago/timeago.dart' as timeago; -import 'package:http/http.dart' as http; class GQLFeedListItemWidget extends StatefulWidget { const GQLFeedListItemWidget({ diff --git a/lib/src/widgets/list_tile_video.dart b/lib/src/widgets/list_tile_video.dart index eaea8746..39a188f5 100644 --- a/lib/src/widgets/list_tile_video.dart +++ b/lib/src/widgets/list_tile_video.dart @@ -97,7 +97,7 @@ class _ListTileVideoState extends State { String priceAndVotes = "\$ ${data.payout?.toStringAsFixed(3)} · 👍 ${data.upVotes} · 👎 ${data.downVotes}"; return Text(priceAndVotes, - style: Theme.of(context).textTheme.bodyText2); + style: Theme.of(context).textTheme.bodyMedium); } else { return const Text('Loading hive payout info'); } @@ -162,7 +162,7 @@ class _ListTileVideoState extends State { height: 45, width: 45, url: widget.userThumbUrl), SizedBox(height: 3), Text(widget.user, - style: Theme.of(context).textTheme.bodyText2), + style: Theme.of(context).textTheme.bodyMedium), ], ), onTap: () { @@ -176,10 +176,10 @@ class _ListTileVideoState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(widget.title, - style: Theme.of(context).textTheme.bodyText1), + style: Theme.of(context).textTheme.bodyLarge), SizedBox(height: 2), Text(widget.subtitle, - style: Theme.of(context).textTheme.bodyText2), + style: Theme.of(context).textTheme.bodyMedium), SizedBox(height: 2), payoutInfo(), ], diff --git a/lib/src/widgets/loading_screen.dart b/lib/src/widgets/loading_screen.dart index f2800b5c..72e412af 100644 --- a/lib/src/widgets/loading_screen.dart +++ b/lib/src/widgets/loading_screen.dart @@ -20,14 +20,14 @@ class LoadingScreen extends StatelessWidget { ), Text( title, - style: Theme.of(context).textTheme.bodyText1, + style: Theme.of(context).textTheme.bodyLarge, ), const SizedBox( height: 10, ), Text( subtitle, - style: Theme.of(context).textTheme.bodyText2, + style: Theme.of(context).textTheme.bodyMedium, ), const Spacer(), ], diff --git a/lib/src/widgets/shorts_xlist_item.dart b/lib/src/widgets/shorts_xlist_item.dart index 3fb42448..01250600 100644 --- a/lib/src/widgets/shorts_xlist_item.dart +++ b/lib/src/widgets/shorts_xlist_item.dart @@ -1,16 +1,7 @@ -import 'dart:convert'; -import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; -import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; -import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; -import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; -import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:flutter/material.dart'; import 'package:timeago/timeago.dart' as timeago; -import 'package:http/http.dart' as http; class ShortsXListItem extends StatefulWidget { const ShortsXListItem({ diff --git a/lib/src/widgets/story_player.dart b/lib/src/widgets/story_player.dart index 9d7b037b..6ad8e68d 100644 --- a/lib/src/widgets/story_player.dart +++ b/lib/src/widgets/story_player.dart @@ -15,7 +15,6 @@ import 'package:acela/src/screens/video_details_screen/hive_upvote_dialog.dart'; import 'package:acela/src/screens/video_details_screen/new_video_details_info.dart'; import 'package:acela/src/screens/video_details_screen/comment/video_details_comments.dart'; import 'package:acela/src/utils/communicator.dart'; -import 'package:acela/src/widgets/user_profile_image.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:better_player/better_player.dart'; import 'package:cached_network_image/cached_network_image.dart'; From d6eac98358770f46c2d6dc05bac1694eea2e64c8 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 12 Feb 2024 01:26:29 +0530 Subject: [PATCH 366/466] offline feature work in progress --- .gitignore | 1 + .idea/libraries/Flutter_Plugins.xml | 48 ++-- ios/Podfile.lock | 70 +++--- lib/main.dart | 30 +-- .../podcast_chapters_controller.dart | 21 +- .../controller/podcast_controller.dart | 31 ++- .../podcast/view/local_podcast_episode.dart | 37 ++- .../new_pod_cast_epidose_player.dart | 66 ++--- .../download_podcast_button.dart | 36 ++- pubspec.lock | 230 +++++++++--------- pubspec.yaml | 2 +- 11 files changed, 269 insertions(+), 303 deletions(-) diff --git a/.gitignore b/.gitignore index 7409d157..ca093c16 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,7 @@ iOSInjectionProject/ .dart_tool .env +dotenv *.env .idea \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 77598f0d..bd28e074 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -13,56 +13,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 1e2982ae..72646376 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -64,10 +64,7 @@ PODS: - Flutter - flutter_secure_storage (6.0.0): - Flutter - - FMDB (2.7.5): - - FMDB/standard (= 2.7.5) - - FMDB/standard (2.7.5) - - FYVideoCompressor (0.0.8) + - FYVideoCompressor (0.0.9) - GCDWebServer (3.5.4): - GCDWebServer/Core (= 3.5.4) - GCDWebServer/Core (3.5.4) @@ -81,15 +78,18 @@ PODS: - ZLPhotoBrowser (= 4.2.5) - just_audio (0.0.1): - Flutter - - libwebp (1.2.4): - - libwebp/demux (= 1.2.4) - - libwebp/mux (= 1.2.4) - - libwebp/webp (= 1.2.4) - - libwebp/demux (1.2.4): + - libwebp (1.3.2): + - libwebp/demux (= 1.3.2) + - libwebp/mux (= 1.3.2) + - libwebp/sharpyuv (= 1.3.2) + - libwebp/webp (= 1.3.2) + - libwebp/demux (1.3.2): - libwebp/webp - - libwebp/mux (1.2.4): + - libwebp/mux (1.3.2): - libwebp/demux - - libwebp/webp (1.2.4) + - libwebp/sharpyuv (1.3.2) + - libwebp/webp (1.3.2): + - libwebp/sharpyuv - package_info_plus (0.4.5): - Flutter - path_provider_foundation (0.0.1): @@ -105,16 +105,16 @@ PODS: - PINCache/Core (3.0.3): - PINOperation (~> 1.2.1) - PINOperation (1.2.2) - - SDWebImage (5.15.7): - - SDWebImage/Core (= 5.15.7) - - SDWebImage/Core (5.15.7) - - Sentry/HybridSDK (8.15.2): - - SentryPrivate (= 8.15.2) + - SDWebImage (5.18.10): + - SDWebImage/Core (= 5.18.10) + - SDWebImage/Core (5.18.10) + - Sentry/HybridSDK (8.19.0): + - SentryPrivate (= 8.19.0) - sentry_flutter (0.0.1): - Flutter - FlutterMacOS - - Sentry/HybridSDK (= 8.15.2) - - SentryPrivate (8.15.2) + - Sentry/HybridSDK (= 8.19.0) + - SentryPrivate (8.19.0) - share_plus (0.0.1): - Flutter - shared_preferences_foundation (0.0.1): @@ -122,7 +122,7 @@ PODS: - FlutterMacOS - sqflite (0.0.3): - Flutter - - FMDB (>= 2.7.5) + - FlutterMacOS - SwiftyGif (5.4.4) - url_launcher_ios (0.0.1): - Flutter @@ -165,7 +165,7 @@ DEPENDENCIES: - sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - - sqflite (from `.symlinks/plugins/sqflite/ios`) + - sqflite (from `.symlinks/plugins/sqflite/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_compress (from `.symlinks/plugins/video_compress/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) @@ -179,7 +179,6 @@ SPEC REPOS: - DKImagePickerController - DKPhotoGallery - ffmpeg-kit-ios-https - - FMDB - FYVideoCompressor - GCDWebServer - HLSCachingReverseProxyServer @@ -236,7 +235,7 @@ EXTERNAL SOURCES: shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" sqflite: - :path: ".symlinks/plugins/sqflite/ios" + :path: ".symlinks/plugins/sqflite/darwin" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" video_compress: @@ -267,33 +266,32 @@ SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_downloader: b7301ae057deadd4b1650dc7c05375f10ff12c39 flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be - FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - FYVideoCompressor: 33a2cdea0ed4daef332077d69388e6ccc0e7d0c3 + FYVideoCompressor: 80e2a90bbc118044038b37b8442f23084c5698bf GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4 HLSCachingReverseProxyServer: 59935e1e0244ad7f3375d75b5ef46e8eb26ab181 - image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 + image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425 images_picker: fa9364e3a7d3083c49f865fcfb2b9e7cdc574d3a just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa - libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef + libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 PINOperation: daa34d4aa1d8449089be7d405b9d974abc4724c6 - SDWebImage: 25bac438318faf37e35650619ebc288a9061d292 - Sentry: 6f5742b4c47c17c9adcf265f6f328cf4a0ed1923 - sentry_flutter: 2c309a1d4b45e59d02cfa15795705687f1e2081b - SentryPrivate: b2f7996f37781080f04a946eb4e377ff63c64195 + SDWebImage: fc8f2d48bbfd72ef39d70e981bd24a3f3be53fec + Sentry: 1ebcaef678a27c8ac515f974cb5425dd1bbdec2f + sentry_flutter: ecdfbedee55337205561cfa782ee02d31ec83e1f + SentryPrivate: 765c9b4ebe9ac1a5fcdc067c5a1cfbf3f10e1677 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 - shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 - sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a + shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 + sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f - url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b + url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe - video_player_avfoundation: e9e6f9cae7d7a6d9b43519b0aab382bca60fcfd1 + video_player_avfoundation: 02011213dab73ae3687df27ce441fbbcc82b5579 video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1 wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f - webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a + webview_flutter_wkwebview: be0f0d33777f1bfd0c9fdcb594786704dbf65f36 ZLPhotoBrowser: 4bfab86b851042e18d7f413284472aa68759626a PODFILE CHECKSUM: c47b194cb97680e602c9d704f278cff245139eb7 diff --git a/lib/main.dart b/lib/main.dart index 160a349e..0a39c430 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -23,9 +23,12 @@ import 'package:upgrader/upgrader.dart'; import 'src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; Future main() async { - await dotenv.load(fileName: ".env"); + await dotenv.load(fileName: "dotenv"); await GetStorage.init(); - await FlutterDownloader.initialize(debug: true); + await FlutterDownloader.initialize( + debug: true, + ignoreSsl: true, + ); GetAudioPlayer getAudioPlayer = GetAudioPlayer(); getAudioPlayer.audioHandler = await AudioService.init( builder: () => AudioPlayerHandlerImpl(), @@ -146,11 +149,9 @@ class _MyAppState extends State { String? hasAuthKey = await storage.read(key: 'hasAuthKey'); String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - String union = - await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; + String union = await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; if (union == 'threespeak-union-graph-ql.sagarkothari88.one') { - await storage.write( - key: 'union', value: GQLCommunicator.defaultGQLServer); + await storage.write(key: 'union', value: GQLCommunicator.defaultGQLServer); union = GQLCommunicator.defaultGQLServer; } String? lang = await storage.read(key: 'lang'); @@ -158,12 +159,7 @@ class _MyAppState extends State { HiveUserData( username: username, postingKey: postingKey, - keychainData: hasId != null && - hasId.isNotEmpty && - hasExpiry != null && - hasExpiry.isNotEmpty && - hasAuthKey != null && - hasAuthKey.isNotEmpty + keychainData: hasId != null && hasId.isNotEmpty && hasExpiry != null && hasExpiry.isNotEmpty && hasAuthKey != null && hasAuthKey.isNotEmpty ? HiveKeychainData( hasAuthKey: hasAuthKey, hasExpiry: hasExpiry, @@ -206,19 +202,13 @@ class AcelaApp extends StatelessWidget { primaryColorLight: Colors.white, primaryColorDark: Colors.black, scaffoldBackgroundColor: Colors.black, - cardTheme: CardTheme( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4))), - color: Colors.grey.shade900), + cardTheme: CardTheme(shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), color: Colors.grey.shade900), ) : ThemeData.light().copyWith( primaryColor: Colors.deepPurple, primaryColorLight: Colors.black, primaryColorDark: Colors.white, - cardTheme: CardTheme( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4))), - color: Colors.grey.shade200), + cardTheme: CardTheme(shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), color: Colors.grey.shade200), ), debugShowCheckedModeBanner: false, ); diff --git a/lib/src/screens/podcast/controller/podcast_chapters_controller.dart b/lib/src/screens/podcast/controller/podcast_chapters_controller.dart index 131ce3ce..9fbd52a5 100644 --- a/lib/src/screens/podcast/controller/podcast_chapters_controller.dart +++ b/lib/src/screens/podcast/controller/podcast_chapters_controller.dart @@ -13,17 +13,18 @@ class PodcastChapterController extends ChangeNotifier { String? title; String? image; - PodcastChapterController( - {required this.chapterUrl, - required this.totalDuration, - required this.audioPlayerHandler}) { + + PodcastChapterController({ + required this.chapterUrl, + required this.totalDuration, + required this.audioPlayerHandler, + }) { _loadChapters(); } void _loadChapters() async { if (chapterUrl != null) { - var result = - await PodCastCommunicator().getPodcastEpisodeChapters(chapterUrl!); + var result = await PodCastCommunicator().getPodcastEpisodeChapters(chapterUrl!); result.removeWhere((element) => element.toc != null); chapters = result; notifyListeners(); @@ -77,7 +78,7 @@ class PodcastChapterController extends ChangeNotifier { int? index = _findNearestLessThan(checkEqual: false); if (index == 0 && currentDuration == 0) { return false; - } else { + } else { return index != null; } } @@ -97,15 +98,13 @@ class PodcastChapterController extends ChangeNotifier { void syncChapters({bool isInteracted = false, bool isReduced = false}) { if (chapters != null && chapters!.isNotEmpty) { if (!isInteracted) { - int index = chapters! - .indexWhere((element) => element.startTime == currentDuration); + int index = chapters!.indexWhere((element) => element.startTime == currentDuration); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { _setChapterTitleAndImage(index); }); } else { if (!isReduced) { - int index = chapters! - .indexWhere((element) => element.startTime == currentDuration); + int index = chapters!.indexWhere((element) => element.startTime == currentDuration); if (index == -1) { int newIndex = chapters!.indexWhere((element) { return element.startTime! > currentDuration; diff --git a/lib/src/screens/podcast/controller/podcast_controller.dart b/lib/src/screens/podcast/controller/podcast_controller.dart index ff46d18a..e668452a 100644 --- a/lib/src/screens/podcast/controller/podcast_controller.dart +++ b/lib/src/screens/podcast/controller/podcast_controller.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:acela/src/models/podcast/podcast_episodes.dart'; import 'package:acela/src/models/podcast/trending_podcast_response.dart'; import 'package:flutter/material.dart'; @@ -15,8 +17,16 @@ class PodcastController extends ChangeNotifier { init(); } - void init() async { - externalDir = await getExternalStorageDirectory(); + void init() { + setupOfflinePath(); + } + + void setupOfflinePath() async { + if (Platform.isAndroid) { + externalDir = await getExternalStorageDirectory(); + } else { + externalDir = await getApplicationDocumentsDirectory(); + } } bool isOffline(String name, String episodeId) { @@ -37,8 +47,7 @@ class PodcastController extends ChangeNotifier { String getOfflineUrl(String url, String episodeId) { for (var item in externalDir.listSync()) { - if (decodeAudioName(item.path) == - decodeAudioName(url, episodeId: episodeId)) { + if (decodeAudioName(item.path) == decodeAudioName(url, episodeId: episodeId)) { return item.path.toString(); } } @@ -121,7 +130,7 @@ class PodcastController extends ChangeNotifier { } //sotre the single podcast episode locally if user likes it - void storeLikedPodcastEpisodeLocally(PodcastEpisode item,{bool forceRemove=false}) { + void storeLikedPodcastEpisodeLocally(PodcastEpisode item, {bool forceRemove = false}) { final String key = _likedPodcastEpisodeLocalKey; if (box.read(key) != null) { List json = box.read(key); @@ -151,15 +160,12 @@ class PodcastController extends ChangeNotifier { } //retrieve the single podcast episodes for liked or offline - List likedOrOfflinepodcastEpisodes( - {required bool isOffline}) { + List likedOrOfflinepodcastEpisodes({required bool isOffline}) { final box = GetStorage(); - final String key = - isOffline ? _offlinePodcastLocalKey : _likedPodcastEpisodeLocalKey; + final String key = isOffline ? _offlinePodcastLocalKey : _likedPodcastEpisodeLocalKey; if (box.read(key) != null) { List json = box.read(key); - List items = - json.map((e) => PodcastEpisode.fromJson(e)).toList(); + List items = json.map((e) => PodcastEpisode.fromJson(e)).toList(); return items; } else { return []; @@ -173,8 +179,7 @@ class PodcastController extends ChangeNotifier { if (decodeAudioName( item.path, ) == - decodeAudioName(episode.enclosureUrl ?? "", - episodeId: episode.id)) { + decodeAudioName(episode.enclosureUrl ?? "", episodeId: episode.id)) { externalDir.listSync()[i].delete(); final String key = _offlinePodcastLocalKey; if (box.read(key) != null) { diff --git a/lib/src/screens/podcast/view/local_podcast_episode.dart b/lib/src/screens/podcast/view/local_podcast_episode.dart index 18559938..bb8332fc 100644 --- a/lib/src/screens/podcast/view/local_podcast_episode.dart +++ b/lib/src/screens/podcast/view/local_podcast_episode.dart @@ -9,8 +9,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class LocalPodcastEpisode extends StatelessWidget { - const LocalPodcastEpisode({Key? key, required this.appData}) - : super(key: key); + const LocalPodcastEpisode({Key? key, required this.appData}) : super(key: key); final HiveUserData appData; @override @@ -39,20 +38,16 @@ class LocalPodcastEpisode extends StatelessWidget { } class LocalEpisodeListView extends StatelessWidget { - const LocalEpisodeListView({Key? key, required this.isOffline}) - : super(key: key); + const LocalEpisodeListView({Key? key, required this.isOffline}) : super(key: key); final bool isOffline; @override Widget build(BuildContext context) { final controller = context.read(); - List items = - controller.likedOrOfflinepodcastEpisodes(isOffline: isOffline); + List items = controller.likedOrOfflinepodcastEpisodes(isOffline: isOffline); if (items.isEmpty) - return Center( - child: Text( - "${isOffline ? "Offline" : "Liked"} Podcast Episode is Empty")); + return Center(child: Text("${isOffline ? "Offline" : "Liked"} Podcast Episode is Empty")); else return ListView.separated( itemBuilder: (c, index) { @@ -64,7 +59,7 @@ class LocalEpisodeListView extends StatelessWidget { if (isOffline) { controller.deleteOfflinePodcastEpisode(item); } else { - controller.storeLikedPodcastEpisodeLocally(item,forceRemove: true); + controller.storeLikedPodcastEpisodeLocally(item, forceRemove: true); } }, child: podcastEpisodeListItem(item, context, controller)); @@ -74,23 +69,24 @@ class LocalEpisodeListView extends StatelessWidget { ); } - ListTile podcastEpisodeListItem( - PodcastEpisode item, BuildContext context, PodcastController controller) { + ListTile podcastEpisodeListItem(PodcastEpisode item, BuildContext context, PodcastController controller) { String url = item.enclosureUrl ?? ""; if (isOffline) { - url = - Uri.parse(controller.getOfflineUrl(item.enclosureUrl ?? "", item.id!)) - .path; + url = Uri.parse(controller.getOfflineUrl(item.enclosureUrl ?? "", item.id!)).path; + item.enclosureUrl = '$url'; } return ListTile( onTap: () { GetAudioPlayer audioPlayer = GetAudioPlayer(); audioPlayer.audioHandler.updateQueue([]); - audioPlayer.audioHandler.addQueueItem(MediaItem( + audioPlayer.audioHandler.addQueueItem( + MediaItem( id: url, title: item.title ?? "", artUri: Uri.parse(item.image ?? ""), - duration: Duration(seconds: item.duration ?? 0))); + duration: Duration(seconds: item.duration ?? 0), + ), + ); var screen = Scaffold( appBar: AppBar( title: ListTile( @@ -103,9 +99,10 @@ class LocalEpisodeListView extends StatelessWidget { ), ), body: SafeArea( - child: NewPodcastEpidosePlayer( - podcastEpisodes: [item], - )), + child: NewPodcastEpidosePlayer( + podcastEpisodes: [item], + ), + ), ); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); diff --git a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart index e3d39ae0..60a86ed6 100644 --- a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart +++ b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart @@ -18,14 +18,12 @@ import 'package:rxdart/rxdart.dart'; import 'package:share_plus/share_plus.dart'; class NewPodcastEpidosePlayer extends StatefulWidget { - const NewPodcastEpidosePlayer({Key? key, required this.podcastEpisodes}) - : super(key: key); + const NewPodcastEpidosePlayer({Key? key, required this.podcastEpisodes}) : super(key: key); final List podcastEpisodes; @override - State createState() => - _NewPodcastEpidosePlayerState(); + State createState() => _NewPodcastEpidosePlayerState(); } class _NewPodcastEpidosePlayerState extends State { @@ -40,20 +38,12 @@ class _NewPodcastEpidosePlayerState extends State { late String originalTitle; late String? originalImage; - Stream get _bufferedPositionStream => _audioHandler.playbackState - .map((state) => state.bufferedPosition) - .distinct(); + Stream get _bufferedPositionStream => _audioHandler.playbackState.map((state) => state.bufferedPosition).distinct(); - Stream get _durationStream => - _audioHandler.mediaItem.map((item) => item?.duration).distinct(); + Stream get _durationStream => _audioHandler.mediaItem.map((item) => item?.duration).distinct(); - Stream get _positionDataStream => - Rx.combineLatest3( - AudioService.position, - _bufferedPositionStream, - _durationStream, - (position, bufferedPosition, duration) => PositionData( - position, bufferedPosition, duration ?? Duration.zero)); + Stream get _positionDataStream => Rx.combineLatest3(AudioService.position, _bufferedPositionStream, + _durationStream, (position, bufferedPosition, duration) => PositionData(position, bufferedPosition, duration ?? Duration.zero)); @override void initState() { @@ -62,10 +52,11 @@ class _NewPodcastEpidosePlayerState extends State { currentPodcastEpisode = widget.podcastEpisodes[currentPodcastIndex]; originalImage = currentPodcastEpisode.image; originalTitle = currentPodcastEpisode.title!; - chapterController = PodcastChapterController( - chapterUrl: currentPodcastEpisode.chaptersUrl, - totalDuration: currentPodcastEpisode.duration ?? 0, - audioPlayerHandler: _audioHandler); + // TO-DO: Ram to handle chapters for offline player + // if (currentPodcastEpisode.enclosureUrl != null && currentPodcastEpisode.enclosureUrl!.startsWith("http")) { + chapterController = PodcastChapterController( + chapterUrl: currentPodcastEpisode.chaptersUrl, totalDuration: currentPodcastEpisode.duration ?? 0, audioPlayerHandler: _audioHandler); + // } queueSubscription = _audioHandler.queueState.listen((event) {}); queueSubscription.onData((data) { _onEpisodeChange(data); @@ -78,10 +69,10 @@ class _NewPodcastEpidosePlayerState extends State { setState(() { currentPodcastIndex = queueState.queueIndex ?? 0; currentPodcastEpisode = widget.podcastEpisodes[currentPodcastIndex]; - chapterController = PodcastChapterController( - chapterUrl: currentPodcastEpisode.chaptersUrl, - totalDuration: currentPodcastEpisode.duration ?? 0, - audioPlayerHandler: _audioHandler); + // if (currentPodcastEpisode.enclosureUrl != null && currentPodcastEpisode.enclosureUrl!.startsWith("http")) { + chapterController = PodcastChapterController( + chapterUrl: currentPodcastEpisode.chaptersUrl, totalDuration: currentPodcastEpisode.duration ?? 0, audioPlayerHandler: _audioHandler); + // } originalTitle = currentPodcastEpisode.title!; originalImage = currentPodcastEpisode.image; }); @@ -110,21 +101,18 @@ class _NewPodcastEpidosePlayerState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Container( - constraints: BoxConstraints( - maxHeight: MediaQuery.of(context).size.height * 0.45), + constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.45), child: Selector( selector: (_, myType) => myType.image, builder: (context, chapterImage, child) { return CachedImage( imageUrl: chapterImage ?? originalImage, - imageHeight: - MediaQuery.of(context).size.height * 0.45, + imageHeight: MediaQuery.of(context).size.height * 0.45, ); }, )), Padding( - padding: const EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10), + padding: const EdgeInsets.symmetric(vertical: 15.0, horizontal: 10), child: Column( children: [ Selector( @@ -154,8 +142,7 @@ class _NewPodcastEpidosePlayerState extends State { chapterController: chapterController, audioPlayerHandler: _audioHandler, positionDataStream: _positionDataStream, - currentPodcastEpisodeDuration: - currentPodcastEpisode.duration), + currentPodcastEpisodeDuration: currentPodcastEpisode.duration), ControlButtons( _audioHandler, chapterController: chapterController, @@ -199,15 +186,12 @@ class _NewPodcastEpidosePlayerState extends State { toastType: "Podcast Episode", disablePadding: true, iconColor: iconColor, - isLiked: podcastController - .isLikedPodcastEpisodePresentLocally(currentPodcastEpisode), + isLiked: podcastController.isLikedPodcastEpisodePresentLocally(currentPodcastEpisode), onAdd: () { - podcastController - .storeLikedPodcastEpisodeLocally(currentPodcastEpisode); + podcastController.storeLikedPodcastEpisodeLocally(currentPodcastEpisode); }, onRemove: () { - podcastController - .storeLikedPodcastEpisodeLocally(currentPodcastEpisode); + podcastController.storeLikedPodcastEpisodeLocally(currentPodcastEpisode); }), IconButton( onPressed: () { @@ -250,9 +234,7 @@ class _NewPodcastEpidosePlayerState extends State { builder: (context) { return SizedBox( height: MediaQuery.of(context).size.height * 0.7, - child: PodcastInfoDescroption( - title: currentPodcastEpisode.title, - description: currentPodcastEpisode.description)); + child: PodcastInfoDescroption(title: currentPodcastEpisode.title, description: currentPodcastEpisode.description)); }, ); } @@ -277,7 +259,7 @@ class _NewPodcastEpidosePlayerState extends State { return ListTile( onTap: () { _audioHandler.skipToQueueItem(index); - Navigator.pop(context); + Navigator.pop(context); }, trailing: Icon(Icons.play_circle_outline_outlined), leading: CachedImage( diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart index 249324ca..1028fc44 100644 --- a/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart @@ -12,11 +12,13 @@ enum DownloadStatus { downloading, downloaded, download } class DownloadPodcastButton extends StatefulWidget { const DownloadPodcastButton({ Key? key, - required this.episode, required this.color, + required this.episode, + required this.color, }) : super(key: key); final PodcastEpisode episode; final Color color; + @override State createState() => _DownloadPodcastButtonState(); } @@ -31,8 +33,7 @@ class _DownloadPodcastButtonState extends State { void initState() { super.initState(); podcastController = context.read(); - IsolateNameServer.registerPortWithName( - _port.sendPort, 'downloader_send_port'); + IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port'); _port.listen((dynamic data) { // String id = data[0]; // DownloadTaskStatus status = (data[1]); @@ -63,8 +64,7 @@ class _DownloadPodcastButtonState extends State { }); } } - print(podcastController.isOffline( - widget.episode.enclosureUrl ?? "", widget.episode.id.toString())); + print(podcastController.isOffline(widget.episode.enclosureUrl ?? "", widget.episode.id.toString())); super.didUpdateWidget(oldWidget); } @@ -77,8 +77,7 @@ class _DownloadPodcastButtonState extends State { @pragma('vm:entry-point') static void downloadCallback(String id, int status, int progress) { - final SendPort? send = - IsolateNameServer.lookupPortByName('downloader_send_port'); + final SendPort? send = IsolateNameServer.lookupPortByName('downloader_send_port'); send!.send([id, status, progress]); } @@ -98,9 +97,7 @@ class _DownloadPodcastButtonState extends State { color: iconColor, ), ); - } else if (podcastController.isOffline( - widget.episode.enclosureUrl ?? "", widget.episode.id.toString()) || - status == DownloadStatus.downloaded) { + } else if (podcastController.isOffline(widget.episode.enclosureUrl ?? "", widget.episode.id.toString()) || status == DownloadStatus.downloaded) { return Icon( Icons.check, color: iconColor, @@ -110,9 +107,9 @@ class _DownloadPodcastButtonState extends State { icon: Icon(Icons.download, color: iconColor), onPressed: () { try { - download(widget.episode.enclosureUrl.toString(), - podcastController.externalDir.path ?? ""); + download(widget.episode.enclosureUrl.toString(), podcastController.externalDir?.path ?? ""); } catch (e) { + print("Error - ${e.toString()}"); setState(() { status = DownloadStatus.download; }); @@ -127,14 +124,11 @@ class _DownloadPodcastButtonState extends State { status = DownloadStatus.downloading; }); FlutterDownloader.enqueue( - url: url, - savedDir: savePath, - fileName: podcastController.decodeAudioName( - widget.episode.enclosureUrl!, - episodeId: widget.episode.id.toString()), - showNotification: true, - openFileFromNotification: true); + url: url, + savedDir: savePath, + fileName: podcastController.decodeAudioName(widget.episode.enclosureUrl!, episodeId: widget.episode.id.toString()), + showNotification: true, + openFileFromNotification: true, + ); } - - } diff --git a/pubspec.lock b/pubspec.lock index 93551627..f9bfa779 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: "direct main" description: name: adaptive_action_sheet - sha256: "2cf53889102f2f476d03da30ef4219a3199f1d9b9f7bf063e2b23cd5aa88ea02" + sha256: "35190411e7136a3c244d58accdf254ac7158eac38e57a62d85b0477a7988f1c5" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.0.3" analyzer: dependency: transitive description: @@ -45,16 +45,16 @@ packages: dependency: transitive description: name: asn1lib - sha256: "21afe4333076c02877d14f4a89df111e658a6d466cbfc802eb705eb91bd5adfd" + sha256: c9c85fedbe2188b95133cbe960e16f5f448860f7133330e272edbbca5893ddc6 url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.5.2" assets_audio_player: dependency: "direct main" description: path: "." ref: master - resolved-ref: "3c89df1cdd076e066002662b3aea43e7d63d7ec6" + resolved-ref: "22a5a19bbddbc54717195a1c0d43a1dfaac9e7b9" url: "https://github.com/florent37/Flutter-AssetsAudioPlayer.git" source: git version: "3.1.1" @@ -175,26 +175,26 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "64e12b0521812d1684b1917bc80945625391cb9bdd4312536b1d69dcb6133ed8" + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" + sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" url: "https://pub.dev" source: hosted - version: "2.4.6" + version: "2.4.8" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185 + sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" url: "https://pub.dev" source: hosted - version: "7.2.11" + version: "7.3.0" built_collection: dependency: transitive description: @@ -207,34 +207,34 @@ packages: dependency: transitive description: name: built_value - sha256: "723b4021e903217dfc445ec4cf5b42e27975aece1fc4ebbc1ca6329c2d9fb54e" + sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6 url: "https://pub.dev" source: hosted - version: "8.7.0" + version: "8.9.0" cached_network_image: dependency: "direct main" description: name: cached_network_image - sha256: f98972704692ba679db144261172a8e20feb145636c617af0eb4022132a6797f + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.3.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: "56aa42a7a01e3c9db8456d9f3f999931f1e05535b5a424271e9a38cabf066613" + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "4.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: "759b9a9f8f6ccbb66c185df805fac107f05730b1dab9c64626d1008cca532257" + sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" carousel_slider: dependency: "direct main" description: @@ -295,10 +295,10 @@ packages: dependency: transitive description: name: code_builder - sha256: "1be9be30396d7e4c0db42c35ea6ccd7cc6a1e19916b5dc64d6ac216b5544d677" + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "4.10.0" collection: dependency: transitive description: @@ -327,10 +327,10 @@ packages: dependency: transitive description: name: cross_file - sha256: "445db18de832dba8d851e287aff8ccf169bed30d2e94243cb54c7d2f1ed2142c" + sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e url: "https://pub.dev" source: hosted - version: "0.3.3+6" + version: "0.3.3+8" crypto: dependency: "direct main" description: @@ -367,10 +367,10 @@ packages: dependency: transitive description: name: dart_style - sha256: abd7625e16f51f554ea244d090292945ec4d4be7bfbaf2ec8cccea568919d334 + sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.3.4" device_info_plus: dependency: "direct main" description: @@ -532,10 +532,10 @@ packages: dependency: "direct main" description: name: flutter_downloader - sha256: "4a03c705dc60b4f537796da937c80fd5bff63b175f4dd99e1539ab3ad5dbeda0" + sha256: e130001cf85d8d7450b8318a4670c19e495dd8c102ad4b15a512e9405e7c451d url: "https://pub.dev" source: hosted - version: "1.11.4" + version: "1.11.6" flutter_lints: dependency: "direct dev" description: @@ -548,10 +548,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: "35108526a233cc0755664d445f8a6b4b61e6f8fe993b3658b80b4a26827fc196" + sha256: "30088ce826b5b9cfbf9e8bece34c716c8a59fa54461dcae1e4ac01a94639e762" url: "https://pub.dev" source: hosted - version: "0.6.18+2" + version: "0.6.18+3" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -630,10 +630,10 @@ packages: dependency: "direct main" description: name: font_awesome_flutter - sha256: "52671aea66da73b58d42ec6d0912b727a42248dd9a7c76d6c20f275783c48c08" + sha256: "275ff26905134bcb59417cf60ad979136f1f8257f2f449914b2c3e05bbb4cd6f" url: "https://pub.dev" source: hosted - version: "10.6.0" + version: "10.7.0" frontend_server_client: dependency: transitive description: @@ -726,10 +726,10 @@ packages: dependency: "direct main" description: name: image - sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d" + sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" url: "https://pub.dev" source: hosted - version: "4.1.4" + version: "4.1.7" image_picker: dependency: "direct main" description: @@ -742,10 +742,10 @@ packages: dependency: transitive description: name: image_picker_android - sha256: "1a27bf4cc0330389cebe465bab08fe6dec97e44015b4899637344bb7297759ec" + sha256: "39f2bfe497e495450c81abcd44b62f56c2a36a37a175da7d137b4454977b51b1" url: "https://pub.dev" source: hosted - version: "0.8.9+2" + version: "0.8.9+3" image_picker_for_web: dependency: transitive description: @@ -758,10 +758,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: eac0a62104fa12feed213596df0321f57ce5a572562f72a68c4ff81e9e4caacf + sha256: fadafce49e8569257a0cad56d24438a6fa1f0cbd7ee0af9b631f7492818a4ca3 url: "https://pub.dev" source: hosted - version: "0.8.9" + version: "0.8.9+1" image_picker_linux: dependency: transitive description: @@ -902,10 +902,10 @@ packages: dependency: transitive description: name: markdown - sha256: acf35edccc0463a9d7384e437c015a3535772e09714cf60e07eeef3a15870dcd + sha256: "1b134d9f8ff2da15cb298efe6cd8b7d2a78958c1b00384ebcbdf13fe340a6c90" url: "https://pub.dev" source: hosted - version: "7.1.1" + version: "7.2.1" matcher: dependency: transitive description: @@ -934,10 +934,10 @@ packages: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" nested: dependency: transitive description: @@ -1006,26 +1006,26 @@ packages: dependency: "direct main" description: name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -1038,10 +1038,10 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: @@ -1094,34 +1094,34 @@ packages: dependency: transitive description: name: petitparser - sha256: eeb2d1428ee7f4170e2bd498827296a18d4e7fc462b71727d111c0ac7707cfa6 + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "6.0.2" platform: dependency: transitive description: name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.8" pointycastle: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.7.4" pool: dependency: transitive description: @@ -1190,18 +1190,18 @@ packages: dependency: transitive description: name: sentry - sha256: e7ded42974bac5f69e4ca4ddc57d30499dd79381838f24b7e8fd9aa4139e7b79 + sha256: a7946f4a90b0feb47214981d881b98149e05f6c576da9f2a2f33945bf561de25 url: "https://pub.dev" source: hosted - version: "7.13.2" + version: "7.16.0" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: d6f55ec7a1f681784165021f749007712a72ff57eadf91e963331b6ae326f089 + sha256: "6db7fa1b076faf2f5dd77d8cc9ef206171f32a290cc638842d78e5d62b441a27" url: "https://pub.dev" source: hosted - version: "7.13.2" + version: "7.16.0" share_plus: dependency: "direct main" description: @@ -1238,10 +1238,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7" + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.5" shared_preferences_linux: dependency: transitive description: @@ -1254,18 +1254,18 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf + sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" shared_preferences_windows: dependency: transitive description: @@ -1299,10 +1299,10 @@ packages: dependency: transitive description: name: source_gen - sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.0" source_helper: dependency: transitive description: @@ -1323,18 +1323,18 @@ packages: dependency: transitive description: name: sqflite - sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a" + sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.2" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: bb4738f15b23352822f4c42a531677e5c6f522e079461fd240ead29d8d8a54a6 + sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" url: "https://pub.dev" source: hosted - version: "2.5.0+2" + version: "2.5.3" stack_trace: dependency: transitive description: @@ -1371,10 +1371,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.0+1" term_glyph: dependency: transitive description: @@ -1395,10 +1395,10 @@ packages: dependency: "direct main" description: name: timeago - sha256: c44b80cbc6b44627c00d76960f2af571f6f50e5dbedef4d9215d455e4335165b + sha256: d3204eb4c788214883380253da7f23485320a58c11d145babc82ad16bf4e7764 url: "https://pub.dev" source: hosted - version: "3.6.0" + version: "3.6.1" timing: dependency: transitive description: @@ -1443,34 +1443,34 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: b1c9e98774adf8820c96fbc7ae3601231d324a7d5ebd8babe27b6dfac91357ba + sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "6.2.4" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def" + sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.2.2" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3 + sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "6.2.4" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "9f2d390e096fdbe1e6e6256f97851e51afc2d9c423d3432f1d6a02a8a9a8b9fd" + sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" url_launcher_macos: dependency: transitive description: @@ -1483,26 +1483,26 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50" + sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.1" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2" + sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.3" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "7754a1ad30ee896b265f8d14078b0513a4dba28d358eabb9d5f339886f4a1adc" + sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" uuid: dependency: "direct main" description: @@ -1539,42 +1539,42 @@ packages: dependency: "direct main" description: name: video_player - sha256: e16f0a83601a78d165dabc17e4dac50997604eb9e4cc76e10fa219046b70cef3 + sha256: fbf28ce8bcfe709ad91b5789166c832cb7a684d14f571a81891858fefb5bb1c2 url: "https://pub.dev" source: hosted - version: "2.8.1" + version: "2.8.2" video_player_android: dependency: transitive description: name: video_player_android - sha256: "3fe89ab07fdbce786e7eb25b58532d6eaf189ceddc091cb66cba712f8d9e8e55" + sha256: "7f8f25d7ad56819a82b2948357f3c3af071f6a678db33833b26ec36bbc221316" url: "https://pub.dev" source: hosted - version: "2.4.10" + version: "2.4.11" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: bc923884640d6dc403050586eb40713cdb8d1d84e6886d8aca50ab04c59124c2 + sha256: "309e3962795e761be010869bae65c0b0e45b5230c5cee1bec72197ca7db040ed" url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.5.6" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - sha256: be72301bf2c0150ab35a8c34d66e5a99de525f6de1e8d27c0672b836fe48f73a + sha256: "236454725fafcacf98f0f39af0d7c7ab2ce84762e3b63f2cbb3ef9a7e0550bc6" url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "6.2.2" video_player_web: dependency: transitive description: name: video_player_web - sha256: ab7a462b07d9ca80bed579e30fb3bce372468f1b78642e0911b10600f2c5cb5b + sha256: "34beb3a07d4331a24f7e7b2f75b8e2b103289038e07e65529699a671b6a6e2cb" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" video_player_web_hls: dependency: "direct main" description: @@ -1667,34 +1667,34 @@ packages: dependency: "direct main" description: name: webview_flutter - sha256: "42393b4492e629aa3a88618530a4a00de8bb46e50e7b3993fedbfdc5352f0dbf" + sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932" url: "https://pub.dev" source: hosted - version: "4.4.2" + version: "4.7.0" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: "8326ee235f87605a2bfc444a4abc897f4abc78d83f054ba7d3d1074ce82b4fbf" + sha256: "3e5f4e9d818086b0d01a66fb1ff9cc72ab0cc58c71980e3d3661c5685ea0efb0" url: "https://pub.dev" source: hosted - version: "3.12.1" + version: "3.15.0" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - sha256: "6d9213c65f1060116757a7c473247c60f3f7f332cac33dc417c9e362a9a13e4f" + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.10.0" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - sha256: accdaaa49a2aca2dc3c3230907988954cdd23fed0a19525d6c9789d380f4dc76 + sha256: "9bf168bccdf179ce90450b5f37e36fe263f591c9338828d6bf09b6f8d0f57f86" url: "https://pub.dev" source: hosted - version: "3.9.4" + version: "3.12.0" win32: dependency: transitive description: @@ -1707,18 +1707,18 @@ packages: dependency: transitive description: name: xdg_directories - sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" xml: dependency: transitive description: name: xml - sha256: af5e77e9b83f2f4adc5d3f0a4ece1c7f45a2467b695c2540381bac793e34e556 + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 url: "https://pub.dev" source: hosted - version: "6.4.2" + version: "6.5.0" yaml: dependency: transitive description: @@ -1728,5 +1728,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0-194.0.dev <4.0.0" - flutter: ">=3.14.0-0" + dart: ">=3.2.3 <4.0.0" + flutter: ">=3.16.6" diff --git a/pubspec.yaml b/pubspec.yaml index 24eeddf5..ce2e6ece 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -127,7 +127,7 @@ flutter: - assets/ctt-logo.png - assets/podcast-index.jpg - assets/pod-cast-logo-round.png - - .env + - dotenv # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg From c5baf86a9b8479466b9dcce83ee174cefe01bd09 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 12 Feb 2024 01:36:06 +0530 Subject: [PATCH 367/466] offline player finally works. --- .../audio_player/audio_player_core_controls.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart index bed683da..6af3b4a9 100644 --- a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart +++ b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart @@ -186,9 +186,15 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler } AudioSource _itemToSource(MediaItem mediaItem) { - final audioSource = AudioSource.uri(Uri.parse(mediaItem.id)); - _mediaItemExpando[audioSource] = mediaItem; - return audioSource; + if (mediaItem.id.startsWith("http")) { + final audioSource = AudioSource.uri(Uri.parse(mediaItem.id)); + _mediaItemExpando[audioSource] = mediaItem; + return audioSource; + } else { + final audioSource = AudioSource.asset(mediaItem.id); + _mediaItemExpando[audioSource] = mediaItem; + return audioSource; + } } List _itemsToSources(List mediaItems) => From 5c3157e2831ba59bcd07e6621d6ca0c57fc6b149 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 12 Feb 2024 10:59:20 +0530 Subject: [PATCH 368/466] login fixed --- lib/main.dart | 1 - lib/src/screens/login/ha_login_screen.dart | 53 +++++++++++++++++++--- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 0a39c430..4e1d04d2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -142,7 +142,6 @@ class _MyAppState extends State { const storage = FlutterSecureStorage(); String? username = await storage.read(key: 'username'); String? postingKey = await storage.read(key: 'postingKey'); - String? cookie = await storage.read(key: 'cookie'); String? accessToken = await storage.read(key: 'accessToken'); String? hasId = await storage.read(key: 'hasId'); String? hasExpiry = await storage.read(key: 'hasExpiry'); diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index c860f4da..769a186c 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -130,6 +130,7 @@ class _HiveAuthLoginScreenState extends State }); break; case "sign_ack": + performSignInWithHAS(); break; case "sign_nack": showError("You denied granting posting authority to 3Speak"); @@ -404,6 +405,7 @@ class _HiveAuthLoginScreenState extends State await storage.write( key: 'username', value: usernameController.text); await storage.write(key: 'postingKey', value: postingKey); + await storage.write(key: 'accessToken', value: loginApiResponse.data); await storage.delete(key: 'hasId'); await storage.delete(key: 'hasExpiry'); await storage.delete(key: 'hasAuthKey'); @@ -535,12 +537,11 @@ class _HiveAuthLoginScreenState extends State var jsonEncodedData = json.encode(socketData); socket.sink.add(jsonEncodedData); } else { - // Posting Auth Data empty = we already have posting authority - // execute acela core login API - performSignInWithAccessTokenHere(); + performSignInWithHAS(); } } else { - // error when getting posting authority details. show error to user. + showMessage( + 'Error getting posting authority details. Please try again.'); } } else { showMessage( @@ -548,12 +549,50 @@ class _HiveAuthLoginScreenState extends State } } - void performSignInWithAccessTokenHere() { + void performSignInWithHAS() async { debugPrint("Signed proof is $signedHash"); debugPrint("Proof of Payload is $proofOfPayload"); debugPrint("Username is ${usernameController.text}"); - // execute another function similar to - // Future login(String userName, String postingKey) async { + var loginApiResponse = await Communicator().login( + usernameController.text, proofOfPayload, signedHash); + String resolution = + await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + String union = await storage.read(key: 'union') ?? + GQLCommunicator.defaultGQLServer; + String? lang = await storage.read(key: 'lang'); + await storage.write( + key: 'username', value: usernameController.text); + await storage.delete(key: 'postingKey'); + await storage.write(key: 'accessToken', value: loginApiResponse.data); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); + await storage.delete(key: 'cookie'); + var data = HiveUserData( + username: usernameController.text, + postingKey: null, + keychainData: null, + accessToken: loginApiResponse.data, + resolution: resolution, + rpc: rpc, + union: union, + loaded: true, + language: lang, + ); + server.updateHiveUserData(data); + Navigator.of(context).pop(); + var screen = GQLFeedScreen( + appData: data, + username: usernameController.text, + ); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).pushReplacement(route); + showMessage( + 'You have successfully logged in as - ${usernameController.text}'); + setState(() { + isLoading = false; + }); } void decryptData(HiveUserData data, String encryptedData) async { From 0073388cf674231742700320779ca648f92eb746 Mon Sep 17 00:00:00 2001 From: sagar Date: Mon, 12 Feb 2024 12:58:56 +0530 Subject: [PATCH 369/466] added firebase analytics --- ios/firebase_app_id_file.json | 7 ++++ lib/firebase_options.dart | 69 +++++++++++++++++++++++++++++++++++ lib/main.dart | 37 ++++++++++++++++--- pubspec.lock | 56 ++++++++++++++++++++++++++++ pubspec.yaml | 2 + 5 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 ios/firebase_app_id_file.json create mode 100644 lib/firebase_options.dart diff --git a/ios/firebase_app_id_file.json b/ios/firebase_app_id_file.json new file mode 100644 index 00000000..fd164f11 --- /dev/null +++ b/ios/firebase_app_id_file.json @@ -0,0 +1,7 @@ +{ + "file_generated_by": "FlutterFire CLI", + "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", + "GOOGLE_APP_ID": "1:252548198943:ios:2fcda030e33a7164355b2a", + "FIREBASE_PROJECT_ID": "acela-9c624", + "GCM_SENDER_ID": "252548198943" +} \ No newline at end of file diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart new file mode 100644 index 00000000..4ce916a9 --- /dev/null +++ b/lib/firebase_options.dart @@ -0,0 +1,69 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for web - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyDZlrKYsD3jlvFkfiXPg3bbVjizqMUqSnE', + appId: '1:252548198943:android:3af79775d4815fab355b2a', + messagingSenderId: '252548198943', + projectId: 'acela-9c624', + storageBucket: 'acela-9c624.appspot.com', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyBhRRZgrQb8WfCKVMjOwC4jnK0XiMuK4YM', + appId: '1:252548198943:ios:2fcda030e33a7164355b2a', + messagingSenderId: '252548198943', + projectId: 'acela-9c624', + storageBucket: 'acela-9c624.appspot.com', + iosClientId: '252548198943-ec3gnethnkvoudaat0lrobmq2t7mve8g.apps.googleusercontent.com', + iosBundleId: 'com.example.acela', + ); +} diff --git a/lib/main.dart b/lib/main.dart index 4e1d04d2..9fd3fa53 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:acela/firebase_options.dart'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/image_resolution_provider.dart'; import 'package:acela/src/global_provider/video_setting_provider.dart'; @@ -6,6 +7,8 @@ import 'package:acela/src/screens/home_screen/new_home_screen.dart'; import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; import 'package:acela/src/screens/upload/video/controller/video_upload_controller.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -24,6 +27,10 @@ import 'src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart Future main() async { await dotenv.load(fileName: "dotenv"); + WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); await GetStorage.init(); await FlutterDownloader.initialize( debug: true, @@ -90,6 +97,12 @@ class _MyAppState extends State { ); } + void logEvent() async { + await FirebaseAnalytics.instance.logEvent( + name: 'app_entry', + ); + } + // This widget is the root of your application. @override Widget build(BuildContext context) { @@ -135,6 +148,7 @@ class _MyAppState extends State { @override void initState() { super.initState(); + logEvent(); _futureToLoadData = loadData(); } @@ -148,9 +162,11 @@ class _MyAppState extends State { String? hasAuthKey = await storage.read(key: 'hasAuthKey'); String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - String union = await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; + String union = + await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; if (union == 'threespeak-union-graph-ql.sagarkothari88.one') { - await storage.write(key: 'union', value: GQLCommunicator.defaultGQLServer); + await storage.write( + key: 'union', value: GQLCommunicator.defaultGQLServer); union = GQLCommunicator.defaultGQLServer; } String? lang = await storage.read(key: 'lang'); @@ -158,7 +174,12 @@ class _MyAppState extends State { HiveUserData( username: username, postingKey: postingKey, - keychainData: hasId != null && hasId.isNotEmpty && hasExpiry != null && hasExpiry.isNotEmpty && hasAuthKey != null && hasAuthKey.isNotEmpty + keychainData: hasId != null && + hasId.isNotEmpty && + hasExpiry != null && + hasExpiry.isNotEmpty && + hasAuthKey != null && + hasAuthKey.isNotEmpty ? HiveKeychainData( hasAuthKey: hasAuthKey, hasExpiry: hasExpiry, @@ -201,13 +222,19 @@ class AcelaApp extends StatelessWidget { primaryColorLight: Colors.white, primaryColorDark: Colors.black, scaffoldBackgroundColor: Colors.black, - cardTheme: CardTheme(shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), color: Colors.grey.shade900), + cardTheme: CardTheme( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4))), + color: Colors.grey.shade900), ) : ThemeData.light().copyWith( primaryColor: Colors.deepPurple, primaryColorLight: Colors.black, primaryColorDark: Colors.white, - cardTheme: CardTheme(shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), color: Colors.grey.shade200), + cardTheme: CardTheme( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4))), + color: Colors.grey.shade200), ), debugShowCheckedModeBanner: false, ); diff --git a/pubspec.lock b/pubspec.lock index f9bfa779..e15ed369 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "64.0.0" + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: "1a52f1afae8ab7ac4741425114713bdbba802f1ce1e0648e167ffcc6e05e96cf" + url: "https://pub.dev" + source: hosted + version: "1.3.21" adaptive_action_sheet: dependency: "direct main" description: @@ -499,6 +507,54 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.3+1" + firebase_analytics: + dependency: "direct main" + description: + name: firebase_analytics + sha256: edb9f9eaecf0e6431e5c12b7fabdb68be3e85ce51f941ccbfa6cb71327e8b535 + url: "https://pub.dev" + source: hosted + version: "10.8.5" + firebase_analytics_platform_interface: + dependency: transitive + description: + name: firebase_analytics_platform_interface + sha256: de4a54353cf58412c6da6b660a0dbad8efacb33b345c0286bc3a2edb869124d8 + url: "https://pub.dev" + source: hosted + version: "3.9.5" + firebase_analytics_web: + dependency: transitive + description: + name: firebase_analytics_web + sha256: "77e4c02ffd0204ccc7856221193265c807b7e056fa62855f973a7f77435b5d41" + url: "https://pub.dev" + source: hosted + version: "0.5.5+17" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "7e049e32a9d347616edb39542cf92cd53fdb4a99fb6af0a0bff327c14cd76445" + url: "https://pub.dev" + source: hosted + version: "2.25.4" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: c437ae5d17e6b5cc7981cf6fd458a5db4d12979905f9aafd1fea930428a9fe63 + url: "https://pub.dev" + source: hosted + version: "5.0.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: "57e61d6010e253b36d38191cefd6199d7849152cdcd234b61ca290cdb278a0ba" + url: "https://pub.dev" + source: hosted + version: "2.11.4" fixnum: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ce2e6ece..959076b2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -90,6 +90,8 @@ dependencies: equatable: ^2.0.5 croppy: ^1.1.4 image: ^4.1.4 + firebase_core: ^2.25.4 + firebase_analytics: ^10.8.5 dev_dependencies: flutter_test: From 6cc4f4d0040f5fd974f1aa7471400fd36937169a Mon Sep 17 00:00:00 2001 From: sagar Date: Mon, 12 Feb 2024 14:12:12 +0530 Subject: [PATCH 370/466] added crashlytics,removed sentry --- lib/main.dart | 17 +++++++---------- pubspec.lock | 16 ++++++++++++++++ pubspec.yaml | 1 + 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 9fd3fa53..65fabb04 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,6 +9,7 @@ import 'package:acela/src/screens/upload/video/controller/video_upload_controlle import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -20,9 +21,7 @@ import 'package:provider/provider.dart'; import 'dart:async'; import 'package:flutter_downloader/flutter_downloader.dart'; import 'package:audio_service/audio_service.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:upgrader/upgrader.dart'; - import 'src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; Future main() async { @@ -45,19 +44,17 @@ Future main() async { androidNotificationOngoing: true, ), ); - WidgetsFlutterBinding.ensureInitialized(); // await Upgrader.clearSavedSettings(); // for debugging await Upgrader.sharedInstance.initialize(); if (kDebugMode) { runApp(const MyApp()); } else { - String dsn = dotenv.get('SENTRY_KEY'); - await SentryFlutter.init( - (options) { - options.dsn = dsn; - }, - appRunner: () => runApp(MyApp()), - ); + FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError; + PlatformDispatcher.instance.onError = (error, stack) { + FirebaseCrashlytics.instance.recordError(error, stack, fatal: true); + return true; + }; + runApp(MyApp()); } } diff --git a/pubspec.lock b/pubspec.lock index e15ed369..11aac35c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -555,6 +555,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.4" + firebase_crashlytics: + dependency: "direct main" + description: + name: firebase_crashlytics + sha256: efd096e4c3d2c568e128505b6e4ce5f5d5a1629f700a4d6fee6bd25b85937dde + url: "https://pub.dev" + source: hosted + version: "3.4.14" + firebase_crashlytics_platform_interface: + dependency: transitive + description: + name: firebase_crashlytics_platform_interface + sha256: "225a54d834a118be262c1f1096d407515e35b99d9b474c987abdcff7663f2b81" + url: "https://pub.dev" + source: hosted + version: "3.6.21" fixnum: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 959076b2..b820f73f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -92,6 +92,7 @@ dependencies: image: ^4.1.4 firebase_core: ^2.25.4 firebase_analytics: ^10.8.5 + firebase_crashlytics: ^3.4.14 dev_dependencies: flutter_test: From 0918eff68da4e3ddd0b368532c2eb96ba30b1f97 Mon Sep 17 00:00:00 2001 From: sagar Date: Mon, 12 Feb 2024 21:15:28 +0530 Subject: [PATCH 371/466] fixed home feed pagination, grid view feeds for tablet --- .../widgets/feed_item_grid_view.dart | 85 +++++ .../widgets/new_feed_list_item.dart | 312 +++++++++--------- .../home_screen/home_screen_feed_list.dart | 185 +++++++---- .../box_loading/video_feed_loader.dart | 53 ++- 4 files changed, 411 insertions(+), 224 deletions(-) create mode 100644 lib/src/screens/home_screen/home_screen_feed_item/widgets/feed_item_grid_view.dart diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/feed_item_grid_view.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/feed_item_grid_view.dart new file mode 100644 index 00000000..747e7098 --- /dev/null +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/feed_item_grid_view.dart @@ -0,0 +1,85 @@ +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart'; +import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; +import 'package:flutter/material.dart'; + +class FeedItemGridView extends StatelessWidget { + const FeedItemGridView({ + Key? key, + required this.screenWidth, + required this.gridCount, + required this.items, + required this.appData, + required this.scrollController, + required this.nextPageLoader, + }) : super(key: key); + + final double screenWidth; + final double gridCount; + final List items; + final HiveUserData appData; + final ScrollController scrollController; + final Widget nextPageLoader; + + @override + Widget build(BuildContext context) { + final screenWidth = MediaQuery.of(context).size.width; + int crossAxisCount = getCrossAxisCount(screenWidth); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 20), + child: CustomScrollView( + controller: scrollController, + slivers: [ + SliverGrid.builder( + itemCount: items.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + childAspectRatio: + MediaQuery.of(context).orientation == Orientation.landscape + ? 1.25 + : 1.4, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + var item = items[index]; + return NewFeedListItem( + key: ValueKey(index), + showVideo: false, + thumbUrl: item.spkvideo?.thumbnailUrl ?? '', + author: item.author?.username ?? '', + title: item.title ?? '', + createdAt: item.createdAt ?? DateTime.now(), + duration: item.spkvideo?.duration ?? 0.0, + comments: item.stats?.numComments ?? 0, + hiveRewards: item.stats?.totalHiveReward, + votes: item.stats?.numVotes, + views: 0, + permlink: item.permlink ?? '', + onTap: () {}, + onUserTap: () {}, + item: item, + appData: appData, + ); + }, + ), + SliverToBoxAdapter( + child: nextPageLoader, + ), + ], + ), + ); + } + + int getCrossAxisCount(double width) { + if (width > 1300) { + return 4; + } else if (width > 974 && width < 1300) { + return 3; + } else if (width > 650 && width < 974) { + return 2; + } else { + return 2; + } + } +} diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart index c6e391f9..79a59167 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart @@ -215,176 +215,178 @@ class _NewFeedListItemState extends State Widget thumbnail = videoThumbnail(); String timeInString = widget.createdAt != null ? "${timeago.format(widget.createdAt!)}" : ""; - return Stack( - children: [ - ListTile( - contentPadding: EdgeInsets.zero, - title: Stack( - children: [ - widget.showVideo && _betterPlayerController != null - ? Stack( - clipBehavior: Clip.none, - children: [ - _videoPlayer(), - _thumbNailAndLoader(thumbnail), - _nextScreenGestureDetector(), - _videoSlider(), - _interactionTools() - ], - ) - : thumbnail, - _timer(), - ], - ), - subtitle: Padding( - padding: const EdgeInsets.only( - top: 10.0, bottom: 5, left: 13, right: 13), - child: Row( - crossAxisAlignment: isTitleOneLine(titleStyle) - ? CrossAxisAlignment.center - : CrossAxisAlignment.start, + return InkWell( + onTap: () { + widget.onTap(); + if (widget.item == null || widget.appData == null) { + var viewModel = VideoDetailsViewModel( + author: widget.author, + permlink: widget.permlink, + ); + var screen = VideoDetailsScreen(vm: viewModel); + var route = MaterialPageRoute(builder: (context) => screen); + Navigator.of(context).push(route); + } else { + _pushToVideoDetailScreen(); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Column( + children: [ + Stack( children: [ - InkWell( - child: ClipOval( - child: CachedImage( - imageHeight: 40, - imageWidth: 40, - loadingIndicatorSize: 25, - imageUrl: server.userOwnerThumb(widget.author), - ), - ), - onTap: () { - widget.onUserTap(); - _pushToUserScreen(); - }, - ), - const SizedBox( - width: 10, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 2.0), - child: Text( - widget.title, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: titleStyle, + widget.showVideo && _betterPlayerController != null + ? Stack( + clipBehavior: Clip.none, + children: [ + _videoPlayer(), + _thumbNailAndLoader(thumbnail), + _nextScreenGestureDetector(), + _videoSlider(), + _interactionTools() + ], + ) + : thumbnail, + _timer(), + ], + ), + Padding( + padding: const EdgeInsets.only( + top: 10.0, bottom: 5, left: 13, right: 13), + child: Row( + crossAxisAlignment: isTitleOneLine(titleStyle) + ? CrossAxisAlignment.center + : CrossAxisAlignment.start, + children: [ + InkWell( + child: ClipOval( + child: CachedImage( + imageHeight: 40, + imageWidth: 40, + loadingIndicatorSize: 25, + imageUrl: server.userOwnerThumb(widget.author), ), ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - InkWell( - child: Row( - children: [ - Text( - '${widget.author}', - style: TextStyle( - color: Theme.of(context) - .primaryColorLight - .withOpacity(0.7), - fontSize: 12), - ), - ], - ), - onTap: () { - widget.onUserTap(); - _pushToUserScreen(); - }, - ), - Expanded( - child: Text( - ' • $timeInString', + onTap: () { + widget.onUserTap(); + _pushToUserScreen(); + }, + ), + const SizedBox( + width: 10, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 2.0), + child: Text( + widget.title, + maxLines: 2, overflow: TextOverflow.ellipsis, - maxLines: 1, - style: TextStyle( - color: Theme.of(context) - .primaryColorLight - .withOpacity(0.7), - fontSize: 12), - )), - const SizedBox( - width: 15, - ), - UpvoteButton( - appData: widget.appData!, - item: widget.item!, - votes: widget.votes, - ), - Padding( - padding: const EdgeInsets.only(top: 2.5, left: 15), - child: Icon( - Icons.comment, - size: 14, - ), + style: titleStyle, ), - Padding( - padding: const EdgeInsets.only( - top: 1.0, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InkWell( + child: Row( + children: [ + Text( + '${widget.author}', + style: TextStyle( + color: Theme.of(context) + .primaryColorLight + .withOpacity(0.7), + fontSize: 12), + ), + ], + ), + onTap: () { + widget.onUserTap(); + _pushToUserScreen(); + }, ), - child: Text( - ' ${widget.comments}', + Expanded( + child: Text( + ' • $timeInString', + overflow: TextOverflow.ellipsis, + maxLines: 1, style: TextStyle( color: Theme.of(context) .primaryColorLight .withOpacity(0.7), fontSize: 12), + )), + const SizedBox( + width: 15, ), - ), - // Padding( - // padding: - // const EdgeInsets.only(left: 10, top: 2.0, right: 5), - // child: SizedBox( - // height: 15, - // width: 25, - // child: FavouriteWidget( - // alignment: Alignment.topCenter, - // disablePadding: true, - // iconSize: 15, - // isLiked: favoriteProvider - // .isLikedVideoPresentLocally(widget.item!), - // onAdd: () { - // favoriteProvider - // .storeLikedVideoLocally(widget.item!); - // }, - // onRemove: () { - // favoriteProvider.storeLikedVideoLocally( - // widget.item!, - // forceRemove: true); - // if (widget.onFavouriteRemoved != null) - // widget.onFavouriteRemoved!(); - // }, - // toastType: 'Video'), - // ), - // ) - ], - ), - ], - )) - ], + UpvoteButton( + appData: widget.appData!, + item: widget.item!, + votes: widget.votes, + ), + Padding( + padding: const EdgeInsets.only(top: 2.5, left: 15), + child: Icon( + Icons.comment, + size: 14, + ), + ), + Padding( + padding: const EdgeInsets.only( + top: 1.0, + ), + child: Text( + ' ${widget.comments}', + style: TextStyle( + color: Theme.of(context) + .primaryColorLight + .withOpacity(0.7), + fontSize: 12), + ), + ), + // Padding( + // padding: + // const EdgeInsets.only(left: 10, top: 2.0, right: 5), + // child: SizedBox( + // height: 15, + // width: 25, + // child: FavouriteWidget( + // alignment: Alignment.topCenter, + // disablePadding: true, + // iconSize: 15, + // isLiked: favoriteProvider + // .isLikedVideoPresentLocally(widget.item!), + // onAdd: () { + // favoriteProvider + // .storeLikedVideoLocally(widget.item!); + // }, + // onRemove: () { + // favoriteProvider.storeLikedVideoLocally( + // widget.item!, + // forceRemove: true); + // if (widget.onFavouriteRemoved != null) + // widget.onFavouriteRemoved!(); + // }, + // toastType: 'Video'), + // ), + // ) + ], + ), + ], + )) + ], + ), ), - ), - onTap: () { - widget.onTap(); - if (widget.item == null || widget.appData == null) { - var viewModel = VideoDetailsViewModel( - author: widget.author, - permlink: widget.permlink, - ); - var screen = VideoDetailsScreen(vm: viewModel); - var route = MaterialPageRoute(builder: (context) => screen); - Navigator.of(context).push(route); - } else { - _pushToVideoDetailScreen(); - } - }, + ], ), - ], + ), ); - } +} bool isTitleOneLine( TextStyle titleStyle, diff --git a/lib/src/screens/home_screen/home_screen_feed_list.dart b/lib/src/screens/home_screen/home_screen_feed_list.dart index ae2314b8..ac73df6e 100644 --- a/lib/src/screens/home_screen/home_screen_feed_list.dart +++ b/lib/src/screens/home_screen/home_screen_feed_list.dart @@ -1,11 +1,13 @@ import 'dart:async'; +import 'dart:developer'; import 'package:acela/src/global_provider/image_resolution_provider.dart'; +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/feed_item_grid_view.dart'; +import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; -import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/widgets/box_loading/video_feed_loader.dart'; -import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart'; import 'package:acela/src/widgets/retry.dart'; import 'package:flutter/material.dart'; import 'package:inview_notifier_list/inview_notifier_list.dart'; @@ -23,13 +25,14 @@ enum HomeScreenFeedType { } class HomeScreenFeedList extends StatefulWidget { - const HomeScreenFeedList( - {Key? key, - required this.appData, - required this.feedType, - this.owner, - this.community, - this.showVideo = true}); + const HomeScreenFeedList({ + Key? key, + required this.appData, + required this.feedType, + this.owner, + this.community, + this.showVideo = true, + }); final HiveUserData appData; final HomeScreenFeedType feedType; @@ -47,7 +50,9 @@ class _HomeScreenFeedListState extends State bool get wantKeepAlive => true; List items = []; + int pageLimit = 50; var firstPageLoaded = false; + var isPageEnded = false; var isLoading = false; var hasFailed = false; final _scrollController = ScrollController(); @@ -86,7 +91,7 @@ class _HomeScreenFeedListState extends State } if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent && - items.length % 50 == 0) { + !isPageEnded) { loadFeed(false); } }); @@ -143,6 +148,7 @@ class _HomeScreenFeedListState extends State } void loadFeed(bool reset) async { + log('loading'); if (isLoading) return; if (!firstPageLoaded) { setState(() { @@ -151,6 +157,9 @@ class _HomeScreenFeedListState extends State }); var newItems = await loadWith(true); setState(() { + if (newItems.length < pageLimit - 1) { + isPageEnded = true; + } items = newItems; isLoading = false; firstPageLoaded = true; @@ -160,10 +169,17 @@ class _HomeScreenFeedListState extends State isLoading = true; if (reset) { firstPageLoaded = false; + isPageEnded = false; } }); var newItems = await loadWith(reset); setState(() { + if (newItems.length < pageLimit - 1) { + isPageEnded = true; + } + if (newItems.isNotEmpty) { + newItems.removeAt(0); + } items = items + newItems; isLoading = false; firstPageLoaded = true; @@ -173,9 +189,13 @@ class _HomeScreenFeedListState extends State @override Widget build(BuildContext context) { + final isGridView = MediaQuery.of(context).size.shortestSide > 600; super.build(context); + var screenWidth = MediaQuery.of(context).size.width; if (isLoading && !firstPageLoaded) { - return VideoFeedLoader(); + return VideoFeedLoader( + isGridView: isGridView, + ); } else if (hasFailed) { return RetryScreen( onRetry: () async { @@ -202,57 +222,74 @@ class _HomeScreenFeedListState extends State ), ); } else { - return NotificationListener( - onNotification: _onScrollStartStopNotification, - child: RefreshIndicator( - onRefresh: () async { - loadFeed(true); - }, - child: InViewNotifierList( - scrollDirection: Axis.vertical, - controller: _scrollController, - initialInViewIds: ['0'], - isInViewPortCondition: (double deltaTop, double deltaBottom, - double viewPortDimension) { - return deltaTop < (0.5 * viewPortDimension) && - deltaBottom > (0.5 * viewPortDimension); - }, - itemCount: - items.length % 50 == 0 ? items.length + 1 : items.length, - onListEndReached: () { - if (!viewOnEnd) { - setState(() { - viewOnEnd = true; - }); - } + return LayoutBuilder( + builder: (context, constraints) { + ; + if (isGridView) { + var gridCount = screenWidth.toInt() / 340; + return FeedItemGridView( + scrollController: _scrollController, + nextPageLoader: _loadNextPageWidget(), + screenWidth: screenWidth, + gridCount: gridCount, + items: items, + appData: widget.appData); + } else { + return _listView(); + } + }, + ); + } + } + } - _setInViewIndex(items.length - 1); - }, - builder: (context, index) { - return LayoutBuilder( - builder: (context, constraints) { - return InViewNotifierWidget( - id: '$index', - builder: (context, isInView, child) { - if (isInView && !viewOnStart && !viewOnEnd) { - _setInViewIndex(index); - } - if (items.length == index) { - return ListTile( - leading: CircularProgressIndicator(), - title: Text('Loading next page'), - subtitle: Text('Please wait...'), - ); - } - var item = items[index]; - return Selector( - selector: (_, myType) => myType.autoPlayVideo, - builder: (context, autoPlay, child) { - return NewFeedListItem( + NotificationListener _listView() { + return NotificationListener( + onNotification: _onScrollStartStopNotification, + child: RefreshIndicator( + onRefresh: () async { + loadFeed(true); + }, + child: InViewNotifierList( + scrollDirection: Axis.vertical, + controller: _scrollController, + initialInViewIds: ['0'], + isInViewPortCondition: + (double deltaTop, double deltaBottom, double viewPortDimension) { + return deltaTop < (0.5 * viewPortDimension) && + deltaBottom > (0.5 * viewPortDimension); + }, + itemCount: items.length, + onListEndReached: () { + if (!viewOnEnd) { + setState(() { + viewOnEnd = true; + }); + } + + _setInViewIndex(items.length - 1); + }, + builder: (context, index) { + return LayoutBuilder( + builder: (context, constraints) { + return InViewNotifierWidget( + id: '$index', + builder: (context, isInView, child) { + if (isInView && !viewOnStart && !viewOnEnd) { + _setInViewIndex(index); + } + var item = items[index]; + return Selector( + selector: (_, myType) => myType.autoPlayVideo, + builder: (context, autoPlay, child) { + return Column( + children: [ + NewFeedListItem( key: ValueKey(index), showVideo: (index == inViewIndex && - !isUserScrolling && - widget.showVideo) && autoPlay, + !isUserScrolling && + widget.showVideo) && + autoPlay, thumbUrl: item.spkvideo?.thumbnailUrl ?? '', author: item.author?.username ?? '', title: item.title ?? '', @@ -267,19 +304,35 @@ class _HomeScreenFeedListState extends State onUserTap: () {}, item: item, appData: widget.appData, - ); - }, + ), + Visibility( + visible: + index == items.length - 1 && !isPageEnded, + child: _loadNextPageWidget()) + ], ); }, ); }, ); }, - ), - ), - ); - } - } + ); + }, + ), + ), + ); + } + + Visibility _loadNextPageWidget() { + return Visibility( + visible: !isPageEnded, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Center( + child: CircularProgressIndicator(), + ), + ), + ); } bool _onScrollStartStopNotification(ScrollNotification scrollNotification) { diff --git a/lib/src/widgets/box_loading/video_feed_loader.dart b/lib/src/widgets/box_loading/video_feed_loader.dart index 23c9bed4..6cdfb970 100644 --- a/lib/src/widgets/box_loading/video_feed_loader.dart +++ b/lib/src/widgets/box_loading/video_feed_loader.dart @@ -2,23 +2,70 @@ import 'package:acela/src/widgets/box_loading/video_item_loader.dart'; import 'package:flutter/material.dart'; class VideoFeedLoader extends StatelessWidget { - const VideoFeedLoader({Key? key}) : super(key: key); + const VideoFeedLoader({Key? key, this.isGridView = false}) : super(key: key); + + final bool isGridView; @override Widget build(BuildContext context) { + final screenWidth = MediaQuery.of(context).size.width; + int crossAxisCount = getCrossAxisCount(screenWidth); + return isGridView + ? _gridViewLoader(crossAxisCount, context) + : _listViewLoader(); + } + + Padding _listViewLoader() { return Padding( - padding: const EdgeInsets.only(top : 10.0), + padding: const EdgeInsets.only(top: 10.0), child: ListView( physics: ClampingScrollPhysics(), shrinkWrap: true, children: List.generate( 6, (index) => Padding( - padding: const EdgeInsets.only(bottom : 10.0), + padding: const EdgeInsets.only(bottom: 10.0), child: VideoItemLoader(), ), ), ), ); } + + Padding _gridViewLoader(int crossAxisCount, BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 20), + child: CustomScrollView( + slivers: [ + SliverGrid.builder( + itemCount: 25, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + childAspectRatio: + MediaQuery.of(context).orientation == Orientation.landscape + ? 1.25 + : 1.4, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + return VideoItemLoader(); + }, + ), + ], + ), + ); + } + + int getCrossAxisCount(double width) { + if (width > 1300) { + return 4; + } else if (width > 974 && width < 1300) { + return 3; + } else if (width > 650 && width < 974) { + return 2; + } else { + return 2; + } + } } From 8bb6242d22376603e72d0c916a0fd4774af878bb Mon Sep 17 00:00:00 2001 From: sagar Date: Tue, 13 Feb 2024 14:19:00 +0530 Subject: [PATCH 372/466] tablet view viewport fix and added grid view for video details suggesitons --- .../widgets/feed_item_grid_view.dart | 100 ++-- .../widgets/new_feed_list_item.dart | 293 ++++++------ .../home_screen/home_screen_feed_list.dart | 3 - .../new_video_details_screen.dart | 433 +++++++++--------- .../box_loading/video_feed_loader.dart | 55 ++- .../box_loading/video_item_loader.dart | 7 +- lib/src/widgets/cached_image.dart | 6 +- 7 files changed, 476 insertions(+), 421 deletions(-) diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/feed_item_grid_view.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/feed_item_grid_view.dart index 747e7098..be6ae309 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/feed_item_grid_view.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/feed_item_grid_view.dart @@ -7,62 +7,26 @@ class FeedItemGridView extends StatelessWidget { const FeedItemGridView({ Key? key, required this.screenWidth, - required this.gridCount, required this.items, required this.appData, - required this.scrollController, - required this.nextPageLoader, + this.scrollController, + this.nextPageLoader, }) : super(key: key); final double screenWidth; - final double gridCount; final List items; final HiveUserData appData; - final ScrollController scrollController; - final Widget nextPageLoader; + final ScrollController? scrollController; + final Widget? nextPageLoader; @override Widget build(BuildContext context) { - final screenWidth = MediaQuery.of(context).size.width; - int crossAxisCount = getCrossAxisCount(screenWidth); return Padding( padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 20), child: CustomScrollView( controller: scrollController, slivers: [ - SliverGrid.builder( - itemCount: items.length, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: crossAxisCount, - childAspectRatio: - MediaQuery.of(context).orientation == Orientation.landscape - ? 1.25 - : 1.4, - crossAxisSpacing: 8, - mainAxisSpacing: 8, - ), - itemBuilder: (context, index) { - var item = items[index]; - return NewFeedListItem( - key: ValueKey(index), - showVideo: false, - thumbUrl: item.spkvideo?.thumbnailUrl ?? '', - author: item.author?.username ?? '', - title: item.title ?? '', - createdAt: item.createdAt ?? DateTime.now(), - duration: item.spkvideo?.duration ?? 0.0, - comments: item.stats?.numComments ?? 0, - hiveRewards: item.stats?.totalHiveReward, - votes: item.stats?.numVotes, - views: 0, - permlink: item.permlink ?? '', - onTap: () {}, - onUserTap: () {}, - item: item, - appData: appData, - ); - }, - ), + FeedItemGridWidget(items: items,appData: appData), SliverToBoxAdapter( child: nextPageLoader, ), @@ -71,7 +35,59 @@ class FeedItemGridView extends StatelessWidget { ); } - int getCrossAxisCount(double width) { + +} + +class FeedItemGridWidget extends StatelessWidget { + const FeedItemGridWidget({ + Key? key, + required this.items, + required this.appData, + }) : super(key: key); + + final List items; + final HiveUserData appData; + + @override + Widget build(BuildContext context) { + var width = MediaQuery.of(context).size.width ; + return SliverGrid.builder( + itemCount: items.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: getCrossAxisCount(width), + childAspectRatio: + MediaQuery.of(context).orientation == Orientation.landscape + ? 1.25 + : 1.4, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + var item = items[index]; + return NewFeedListItem( + isGridView: true, + key: ValueKey(index), + showVideo: false, + thumbUrl: item.spkvideo?.thumbnailUrl ?? '', + author: item.author?.username ?? '', + title: item.title ?? '', + createdAt: item.createdAt ?? DateTime.now(), + duration: item.spkvideo?.duration ?? 0.0, + comments: item.stats?.numComments ?? 0, + hiveRewards: item.stats?.totalHiveReward, + votes: item.stats?.numVotes, + views: 0, + permlink: item.permlink ?? '', + onTap: () {}, + onUserTap: () {}, + item: item, + appData: appData, + ); + }, + ); + } + + int getCrossAxisCount(double width) { if (width > 1300) { return 4; } else if (width > 974 && width < 1300) { diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart index 79a59167..fc9983c2 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart @@ -44,7 +44,8 @@ class NewFeedListItem extends StatefulWidget { this.item, this.appData, this.showVideo = false, - this.onFavouriteRemoved}) + this.onFavouriteRemoved, + this.isGridView = false}) : super(key: key); final DateTime? createdAt; @@ -63,6 +64,7 @@ class NewFeedListItem extends StatefulWidget { final HiveUserData? appData; final bool showVideo; final VoidCallback? onFavouriteRemoved; + final bool isGridView; @override State createState() => _NewFeedListItemState(); @@ -203,7 +205,8 @@ class _NewFeedListItemState extends State builder: (context, value, child) { return CachedImage( imageUrl: Utilities.getProxyImage(value, widget.thumbUrl), - imageHeight: 230, + fit: widget.isGridView ? BoxFit.cover : null, + imageHeight: !widget.isGridView ? 230 : null, imageWidth: double.infinity, ); }); @@ -234,159 +237,171 @@ class _NewFeedListItemState extends State padding: const EdgeInsets.symmetric(vertical: 8), child: Column( children: [ - Stack( - children: [ - widget.showVideo && _betterPlayerController != null - ? Stack( - clipBehavior: Clip.none, - children: [ - _videoPlayer(), - _thumbNailAndLoader(thumbnail), - _nextScreenGestureDetector(), - _videoSlider(), - _interactionTools() - ], - ) - : thumbnail, - _timer(), - ], - ), - Padding( - padding: const EdgeInsets.only( - top: 10.0, bottom: 5, left: 13, right: 13), - child: Row( - crossAxisAlignment: isTitleOneLine(titleStyle) - ? CrossAxisAlignment.center - : CrossAxisAlignment.start, - children: [ - InkWell( - child: ClipOval( - child: CachedImage( - imageHeight: 40, - imageWidth: 40, - loadingIndicatorSize: 25, - imageUrl: server.userOwnerThumb(widget.author), - ), - ), - onTap: () { - widget.onUserTap(); - _pushToUserScreen(); - }, - ), - const SizedBox( - width: 10, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 2.0), - child: Text( - widget.title, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: titleStyle, + widget.isGridView + ? Expanded( + child: _videoStack(thumbnail), + ) + : _videoStack(thumbnail), + SizedBox( + height:widget.isGridView ? 75 : null, + child: Padding( + padding: const EdgeInsets.only( + top: 10.0, bottom: 5, left: 13, right: 13), + child: Row( + crossAxisAlignment:!widget.isGridView && isTitleOneLine(titleStyle) + ? CrossAxisAlignment.center + : CrossAxisAlignment.start, + children: [ + InkWell( + child: ClipOval( + child: CachedImage( + imageHeight: 40, + imageWidth: 40, + loadingIndicatorSize: 25, + imageUrl: server.userOwnerThumb(widget.author), ), ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - InkWell( - child: Row( - children: [ - Text( - '${widget.author}', - style: TextStyle( - color: Theme.of(context) - .primaryColorLight - .withOpacity(0.7), - fontSize: 12), - ), - ], - ), - onTap: () { - widget.onUserTap(); - _pushToUserScreen(); - }, - ), - Expanded( - child: Text( - ' • $timeInString', + onTap: () { + widget.onUserTap(); + _pushToUserScreen(); + }, + ), + const SizedBox( + width: 10, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 2.0), + child: Text( + widget.title, + maxLines: 2, overflow: TextOverflow.ellipsis, - maxLines: 1, - style: TextStyle( - color: Theme.of(context) - .primaryColorLight - .withOpacity(0.7), - fontSize: 12), - )), - const SizedBox( - width: 15, - ), - UpvoteButton( - appData: widget.appData!, - item: widget.item!, - votes: widget.votes, - ), - Padding( - padding: const EdgeInsets.only(top: 2.5, left: 15), - child: Icon( - Icons.comment, - size: 14, - ), + style: titleStyle, ), - Padding( - padding: const EdgeInsets.only( - top: 1.0, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InkWell( + child: Row( + children: [ + Text( + '${widget.author}', + style: TextStyle( + color: Theme.of(context) + .primaryColorLight + .withOpacity(0.7), + fontSize: 12), + ), + ], + ), + onTap: () { + widget.onUserTap(); + _pushToUserScreen(); + }, ), - child: Text( - ' ${widget.comments}', + Expanded( + child: Text( + ' • $timeInString', + overflow: TextOverflow.ellipsis, + maxLines: 1, style: TextStyle( color: Theme.of(context) .primaryColorLight .withOpacity(0.7), fontSize: 12), + )), + const SizedBox( + width: 15, ), - ), - // Padding( - // padding: - // const EdgeInsets.only(left: 10, top: 2.0, right: 5), - // child: SizedBox( - // height: 15, - // width: 25, - // child: FavouriteWidget( - // alignment: Alignment.topCenter, - // disablePadding: true, - // iconSize: 15, - // isLiked: favoriteProvider - // .isLikedVideoPresentLocally(widget.item!), - // onAdd: () { - // favoriteProvider - // .storeLikedVideoLocally(widget.item!); - // }, - // onRemove: () { - // favoriteProvider.storeLikedVideoLocally( - // widget.item!, - // forceRemove: true); - // if (widget.onFavouriteRemoved != null) - // widget.onFavouriteRemoved!(); - // }, - // toastType: 'Video'), - // ), - // ) - ], - ), - ], - )) - ], + UpvoteButton( + appData: widget.appData!, + item: widget.item!, + votes: widget.votes, + ), + Padding( + padding: + const EdgeInsets.only(top: 2.5, left: 15), + child: Icon( + Icons.comment, + size: 14, + ), + ), + Padding( + padding: const EdgeInsets.only( + top: 1.0, + ), + child: Text( + ' ${widget.comments}', + style: TextStyle( + color: Theme.of(context) + .primaryColorLight + .withOpacity(0.7), + fontSize: 12), + ), + ), + // Padding( + // padding: + // const EdgeInsets.only(left: 10, top: 2.0, right: 5), + // child: SizedBox( + // height: 15, + // width: 25, + // child: FavouriteWidget( + // alignment: Alignment.topCenter, + // disablePadding: true, + // iconSize: 15, + // isLiked: favoriteProvider + // .isLikedVideoPresentLocally(widget.item!), + // onAdd: () { + // favoriteProvider + // .storeLikedVideoLocally(widget.item!); + // }, + // onRemove: () { + // favoriteProvider.storeLikedVideoLocally( + // widget.item!, + // forceRemove: true); + // if (widget.onFavouriteRemoved != null) + // widget.onFavouriteRemoved!(); + // }, + // toastType: 'Video'), + // ), + // ) + ], + ), + ], + )) + ], + ), ), ), ], ), ), ); -} + } + + Stack _videoStack(Widget thumbnail) { + return Stack( + children: [ + widget.showVideo && _betterPlayerController != null + ? Stack( + clipBehavior: Clip.none, + children: [ + _videoPlayer(), + _thumbNailAndLoader(thumbnail), + _nextScreenGestureDetector(), + _videoSlider(), + _interactionTools() + ], + ) + : widget.isGridView ? Positioned.fill(child: thumbnail) : thumbnail, + _timer(), + ], + ); + } bool isTitleOneLine( TextStyle titleStyle, @@ -512,7 +527,7 @@ class _NewFeedListItemState extends State return Hero( tag: '${widget.item?.author}/${widget.item?.permlink}', child: SizedBox( - height: 230, + height: !widget.isGridView ? 230 : null, child: BetterPlayer( controller: _betterPlayerController!, ), diff --git a/lib/src/screens/home_screen/home_screen_feed_list.dart b/lib/src/screens/home_screen/home_screen_feed_list.dart index ac73df6e..f4d1ea07 100644 --- a/lib/src/screens/home_screen/home_screen_feed_list.dart +++ b/lib/src/screens/home_screen/home_screen_feed_list.dart @@ -224,14 +224,11 @@ class _HomeScreenFeedListState extends State } else { return LayoutBuilder( builder: (context, constraints) { - ; if (isGridView) { - var gridCount = screenWidth.toInt() / 340; return FeedItemGridView( scrollController: _scrollController, nextPageLoader: _loadNextPageWidget(), screenWidth: screenWidth, - gridCount: gridCount, items: items, appData: widget.appData); } else { diff --git a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart index 45637e3d..5d4c6f47 100644 --- a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart +++ b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/image_resolution_provider.dart'; import 'package:acela/src/global_provider/video_setting_provider.dart'; +import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/feed_item_grid_view.dart'; import 'package:acela/src/screens/podcast/widgets/favourite.dart'; import 'package:acela/src/screens/trending_tags/trending_tag_videos.dart'; import 'package:acela/src/screens/video_details_screen/new_video_details/video_detail_favourite_provider.dart'; @@ -230,18 +231,20 @@ class _NewVideoDetailsScreenState extends State { }); } - Widget _videoPlayerStack(double screenWidth) { - return Hero( - tag: '${widget.item.author}/${widget.item.permlink}', - child: SizedBox( - height: 230, - child: Stack( - children: [ - BetterPlayer( - controller: _betterPlayerController, - ), - _fullScreenButtonForIos(), - ], + Widget _videoPlayerStack(double screenHeight,bool isGridView) { + return SliverToBoxAdapter( + child: Hero( + tag: '${widget.item.author}/${widget.item.permlink}', + child: SizedBox( + height:isGridView ? screenHeight * 0.4 : 230, + child: Stack( + children: [ + BetterPlayer( + controller: _betterPlayerController, + ), + _fullScreenButtonForIos(), + ], + ), ), ), ); @@ -295,53 +298,55 @@ class _NewVideoDetailsScreenState extends State { String timeInString = widget.item.createdAt != null ? "${timeago.format(widget.item.createdAt!)}" : ""; - return Padding( - padding: const EdgeInsets.only(top: 0.0, bottom: 5), - child: ListTile( - contentPadding: EdgeInsets.only(top: 0, left: 15, right: 15), - dense: true, - splashColor: Colors.transparent, - onTap: () { - var screen = UserChannelScreen( - owner: widget.item.author?.username ?? "sagarkothari88"); - var route = MaterialPageRoute(builder: (_) => screen); - Navigator.of(context).push(route); - }, - leading: ClipOval( - child: CachedImage( - imageUrl: - 'https://images.hive.blog/u/${widget.item.author?.username ?? 'sagarkothari88'}/avatar', - imageHeight: 40, - imageWidth: 40, + return SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.only(top: 10.0, bottom: 5), + child: ListTile( + contentPadding: EdgeInsets.only(top: 0, left: 15, right: 15), + dense: true, + splashColor: Colors.transparent, + onTap: () { + var screen = UserChannelScreen( + owner: widget.item.author?.username ?? "sagarkothari88"); + var route = MaterialPageRoute(builder: (_) => screen); + Navigator.of(context).push(route); + }, + leading: ClipOval( + child: CachedImage( + imageUrl: + 'https://images.hive.blog/u/${widget.item.author?.username ?? 'sagarkothari88'}/avatar', + imageHeight: 40, + imageWidth: 40, + ), ), - ), - title: Text( - widget.item.title ?? 'No title', - style: TextStyle( - color: Theme.of(context).primaryColorLight, - fontWeight: FontWeight.bold, - fontSize: 17), - ), - subtitle: Row( - children: [ - Expanded( - child: Text( - widget.item.author?.username ?? "sagarkothari88", - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle(color: Theme.of(context).primaryColorLight), + title: Text( + widget.item.title ?? 'No title', + style: TextStyle( + color: Theme.of(context).primaryColorLight, + fontWeight: FontWeight.bold, + fontSize: 17), + ), + subtitle: Row( + children: [ + Expanded( + child: Text( + widget.item.author?.username ?? "sagarkothari88", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: Theme.of(context).primaryColorLight), + ), ), - ), - const SizedBox( - width: 10, - ), - Text( - timeInString, - style: TextStyle( - color: Theme.of(context).primaryColorLight.withOpacity(0.7), - fontWeight: FontWeight.w500), - ), - ], + const SizedBox( + width: 10, + ), + Text( + timeInString, + style: TextStyle( + color: Theme.of(context).primaryColorLight.withOpacity(0.7), + fontWeight: FontWeight.w500), + ), + ], + ), ), ), ); @@ -521,70 +526,74 @@ class _NewVideoDetailsScreenState extends State { Color color = Theme.of(context).primaryColorLight; String votes = "${widget.item.stats?.numVotes ?? 0}"; String comments = "${widget.item.stats?.numComments ?? 0}"; - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - onPressed: () { - infoPressed(width); - }, - icon: Icon(Icons.info, color: color), - ), - Row( - children: [ - IconButton( - onPressed: () { - seeCommentsPressed(); - }, - icon: Icon(Icons.comment, color: color), - ), - Text(comments, - style: TextStyle( - color: - Theme.of(context).primaryColorLight.withOpacity(0.7), - fontSize: 13)) - ], - ), - Row( - children: [ - IconButton( - onPressed: () { - if (postInfo != null) { - showVoters(); - } - }, - icon: Icon( - isUserVoted() ? Icons.thumb_up : Icons.thumb_up_outlined, - color: color), - ), - Text(votes, - style: TextStyle( - color: - Theme.of(context).primaryColorLight.withOpacity(0.7), - fontSize: 13)) - ], - ), - IconButton( - onPressed: () { - Share.share( - 'https://3speak.tv/watch?v=${widget.item.author?.username ?? 'sagarkothari88'}/${widget.item.permlink}'); - }, - icon: Icon(Icons.share, color: color), - ), - FavouriteWidget( - toastType: "Video", - iconColor: color, - isLiked: provider.isLikedVideoPresentLocally(widget.item), - onAdd: () { - provider.storeLikedVideoLocally(widget.item); + return SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + onPressed: () { + infoPressed(width); }, - onRemove: () { - provider.storeLikedVideoLocally(widget.item); - }) - ], + icon: Icon(Icons.info, color: color), + ), + Row( + children: [ + IconButton( + onPressed: () { + seeCommentsPressed(); + }, + icon: Icon(Icons.comment, color: color), + ), + Text(comments, + style: TextStyle( + color: Theme.of(context) + .primaryColorLight + .withOpacity(0.7), + fontSize: 13)) + ], + ), + Row( + children: [ + IconButton( + onPressed: () { + if (postInfo != null) { + showVoters(); + } + }, + icon: Icon( + isUserVoted() ? Icons.thumb_up : Icons.thumb_up_outlined, + color: color), + ), + Text(votes, + style: TextStyle( + color: Theme.of(context) + .primaryColorLight + .withOpacity(0.7), + fontSize: 13)) + ], + ), + IconButton( + onPressed: () { + Share.share( + 'https://3speak.tv/watch?v=${widget.item.author?.username ?? 'sagarkothari88'}/${widget.item.permlink}'); + }, + icon: Icon(Icons.share, color: color), + ), + FavouriteWidget( + toastType: "Video", + iconColor: color, + isLiked: provider.isLikedVideoPresentLocally(widget.item), + onAdd: () { + provider.storeLikedVideoLocally(widget.item); + }, + onRemove: () { + provider.storeLikedVideoLocally(widget.item); + }) + ], + ), ), ); } @@ -605,75 +614,105 @@ class _NewVideoDetailsScreenState extends State { Widget _chipList() { List tags = widget.item.tags ?? ['threespeak', 'video', 'threeshorts']; - return Padding( - padding: const EdgeInsets.only(bottom: 15.0, top: 5), - child: SizedBox( - height: 33, - child: ListView.builder( - padding: EdgeInsets.symmetric(horizontal: 8), - scrollDirection: Axis.horizontal, - itemCount: tags.length, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.only(right: 8), - child: InkWell( - borderRadius: BorderRadius.all( - Radius.circular(18), - ), - onTap: () { - var screen = TrendingTagVideos(tag: tags[index]); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - child: Container( - alignment: Alignment.center, - padding: EdgeInsets.symmetric(vertical: 5, horizontal: 15), - decoration: BoxDecoration( - border: Border.all( - color: Theme.of(context) - .primaryColorLight - .withOpacity(0.3)), - borderRadius: BorderRadius.all( - Radius.circular(18), - ), + return SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.only(bottom: 15.0, top: 5), + child: SizedBox( + height: 33, + child: ListView.builder( + padding: EdgeInsets.symmetric(horizontal: 8), + scrollDirection: Axis.horizontal, + itemCount: tags.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.only(right: 8), + child: InkWell( + borderRadius: BorderRadius.all( + Radius.circular(18), ), - child: Text( - tags[index], - style: TextStyle( - color: Theme.of(context).primaryColorLight, - fontSize: 14, - fontWeight: FontWeight.w500), + onTap: () { + var screen = TrendingTagVideos(tag: tags[index]); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + child: Container( + alignment: Alignment.center, + padding: + EdgeInsets.symmetric(vertical: 5, horizontal: 15), + decoration: BoxDecoration( + border: Border.all( + color: Theme.of(context) + .primaryColorLight + .withOpacity(0.3)), + borderRadius: BorderRadius.all( + Radius.circular(18), + ), + ), + child: Text( + tags[index], + style: TextStyle( + color: Theme.of(context).primaryColorLight, + fontSize: 14, + fontWeight: FontWeight.w500), + ), ), ), - ), - ); - }), + ); + }), + ), ), ); } - Widget _listView( - double screenWidth, - ) { - var text = widget.item.spkvideo?.body ?? 'No content'; - if (text.length > 100) { - text = text.substring(0, 96); - text = "$text..."; + void changeControlsVisibility(bool showControls) { + if (widget.betterPlayerController != null) { + widget.betterPlayerController!.setControlsAlwaysVisible(false); + widget.betterPlayerController!.setControlsEnabled(showControls); + widget.betterPlayerController!.setControlsVisibility(showControls); } - return Expanded( - child: ListView.separated( - padding: EdgeInsets.only(top: 10), - itemBuilder: (c, i) { - if (i == 0) { - return _userInfo(); - } else if (i == 1) { - return _actionBar(screenWidth); - } else if (i == 2) { - return _chipList(); - } else if (i == 3 && isSuggestionsLoading) { - return VideoFeedLoader(); - } - var item = suggestions[i - 3]; + } + + @override + Widget build(BuildContext context) { + var width = MediaQuery.of(context).size.width; + var height = MediaQuery.of(context).size.height; + final isGridView = MediaQuery.of(context).size.shortestSide > 600; + return PopScope( + onPopInvoked: (value) { + changeControlsVisibility(false); + }, + child: Scaffold( + body: SafeArea( + child: CustomScrollView( + slivers: [ + _videoPlayerStack(height,isGridView), + _userInfo(), + _actionBar(width), + _chipList(), + isSuggestionsLoading + ? VideoFeedLoader( + isSliver: true, + isGridView: isGridView, + ) + : + isGridView + ? _sliverGridView() + : _sliverListView(), + ], + )), + ), + ); + } + + Widget _sliverGridView() { + return FeedItemGridWidget(items: suggestions, appData: widget.appData); + } + + SliverList _sliverListView() { + return SliverList( + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + var item = suggestions[index]; return NewFeedListItem( thumbUrl: item.spkvideo?.thumbnailUrl ?? '', author: item.author?.username ?? '', @@ -691,37 +730,7 @@ class _NewVideoDetailsScreenState extends State { appData: widget.appData, ); }, - separatorBuilder: (c, i) => - const Divider(height: 0, color: Colors.transparent), - itemCount: isSuggestionsLoading ? 4 : 3 + suggestions.length, - ), - ); - } - - void changeControlsVisibility(bool showControls) { - if (widget.betterPlayerController != null) { - widget.betterPlayerController!.setControlsAlwaysVisible(false); - widget.betterPlayerController!.setControlsEnabled(showControls); - widget.betterPlayerController!.setControlsVisibility(showControls); - } - } - - @override - Widget build(BuildContext context) { - var width = MediaQuery.of(context).size.width; - return PopScope( - onPopInvoked: (value) { - changeControlsVisibility(false); - }, - child: Scaffold( - body: SafeArea( - child: Column( - children: [ - _videoPlayerStack(width), - _listView(width), - ], - ), - ), + childCount: suggestions.length, ), ); } diff --git a/lib/src/widgets/box_loading/video_feed_loader.dart b/lib/src/widgets/box_loading/video_feed_loader.dart index 6cdfb970..0ea85558 100644 --- a/lib/src/widgets/box_loading/video_feed_loader.dart +++ b/lib/src/widgets/box_loading/video_feed_loader.dart @@ -2,17 +2,28 @@ import 'package:acela/src/widgets/box_loading/video_item_loader.dart'; import 'package:flutter/material.dart'; class VideoFeedLoader extends StatelessWidget { - const VideoFeedLoader({Key? key, this.isGridView = false}) : super(key: key); + const VideoFeedLoader( + {Key? key, this.isGridView = false, this.isSliver = false}) + : super(key: key); final bool isGridView; + final bool isSliver; @override Widget build(BuildContext context) { final screenWidth = MediaQuery.of(context).size.width; int crossAxisCount = getCrossAxisCount(screenWidth); return isGridView - ? _gridViewLoader(crossAxisCount, context) - : _listViewLoader(); + ? isSliver + ? SliverFillRemaining( + child: _gridViewLoader(crossAxisCount, context), + ) + : _gridViewLoader(crossAxisCount, context) + : isSliver + ? SliverToBoxAdapter( + child: _listViewLoader(), + ) + : _listViewLoader(); } Padding _listViewLoader() { @@ -25,7 +36,9 @@ class VideoFeedLoader extends StatelessWidget { 6, (index) => Padding( padding: const EdgeInsets.only(bottom: 10.0), - child: VideoItemLoader(), + child: VideoItemLoader( + isGridView: false, + ), ), ), ), @@ -35,24 +48,22 @@ class VideoFeedLoader extends StatelessWidget { Padding _gridViewLoader(int crossAxisCount, BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 20), - child: CustomScrollView( - slivers: [ - SliverGrid.builder( - itemCount: 25, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: crossAxisCount, - childAspectRatio: - MediaQuery.of(context).orientation == Orientation.landscape - ? 1.25 - : 1.4, - crossAxisSpacing: 8, - mainAxisSpacing: 8, - ), - itemBuilder: (context, index) { - return VideoItemLoader(); - }, - ), - ], + child: GridView.builder( + itemCount: 25, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + childAspectRatio: + MediaQuery.of(context).orientation == Orientation.landscape + ? 1.25 + : 1.4, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + return VideoItemLoader( + isGridView: isGridView, + ); + }, ), ); } diff --git a/lib/src/widgets/box_loading/video_item_loader.dart b/lib/src/widgets/box_loading/video_item_loader.dart index e839a0db..167d06c7 100644 --- a/lib/src/widgets/box_loading/video_item_loader.dart +++ b/lib/src/widgets/box_loading/video_item_loader.dart @@ -3,8 +3,9 @@ import 'package:acela/src/widgets/box_loading/box_trail.dart'; import 'package:flutter/material.dart'; class VideoItemLoader extends StatefulWidget { - const VideoItemLoader({Key? key}); + const VideoItemLoader({Key? key, required this.isGridView}); + final bool isGridView; @override State createState() => _VideoItemLoaderState(); } @@ -20,6 +21,10 @@ class _VideoItemLoaderState extends State { return BoxLoadingIndicator( child: Column( children: [ + widget.isGridView ? Expanded(child: BoxTrail( + shape: BoxShape.rectangle, + height: 230, + ),) : BoxTrail( shape: BoxShape.rectangle, height: 230, diff --git a/lib/src/widgets/cached_image.dart b/lib/src/widgets/cached_image.dart index 99cf5af9..9655ee22 100644 --- a/lib/src/widgets/cached_image.dart +++ b/lib/src/widgets/cached_image.dart @@ -7,13 +7,15 @@ class CachedImage extends StatelessWidget { required this.imageUrl, this.imageHeight, this.imageWidth, - this.loadingIndicatorSize}) + this.loadingIndicatorSize, + this.fit}) : super(key: key); final String? imageUrl; final double? imageHeight; final double? imageWidth; final double? loadingIndicatorSize; + final BoxFit? fit; @override Widget build(BuildContext context) { @@ -25,7 +27,7 @@ class CachedImage extends StatelessWidget { imageUrl: imageUrl ?? '', height: imageHeight, width: imageWidth, - fit: imageHeight != null ? BoxFit.cover : null, + fit: fit ?? (imageHeight != null ? BoxFit.cover : null), // progressIndicatorBuilder: (context, url, downloadProgress) => // imageHeight != null // ? Center( From a9958074709b5d7542c64b2e3f73305949f38c8e Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 14 Feb 2024 11:29:31 +0530 Subject: [PATCH 373/466] If posting authority NOT given, allow user to upvote & comment --- .idea/libraries/Flutter_Plugins.xml | 7 +- android/app/build.gradle | 2 +- ios/Podfile.lock | 161 ++++++++++++- ios/Runner.xcodeproj/project.pbxproj | 24 ++ .../models/user_stream/hive_user_stream.dart | 1 + lib/src/screens/login/ha_login_screen.dart | 227 +++++++----------- .../hive_upvote_dialog.dart | 2 +- pubspec.lock | 4 +- 8 files changed, 282 insertions(+), 146 deletions(-) diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index bd28e074..90c6ae68 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -46,7 +46,6 @@ - @@ -63,6 +62,12 @@ + + + + + + diff --git a/android/app/build.gradle b/android/app/build.gradle index a0b7db70..e7912dec 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -71,7 +71,7 @@ android { release { minifyEnabled false shrinkResources false - signingConfig signingConfigs.release + // signingConfig signingConfigs.release } } buildFeatures { diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 72646376..050cfbd7 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -59,6 +59,74 @@ PODS: - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter + - Firebase/Analytics (10.20.0): + - Firebase/Core + - Firebase/Core (10.20.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 10.20.0) + - Firebase/CoreOnly (10.20.0): + - FirebaseCore (= 10.20.0) + - Firebase/Crashlytics (10.20.0): + - Firebase/CoreOnly + - FirebaseCrashlytics (~> 10.20.0) + - firebase_analytics (10.8.5): + - Firebase/Analytics (= 10.20.0) + - firebase_core + - Flutter + - firebase_core (2.25.4): + - Firebase/CoreOnly (= 10.20.0) + - Flutter + - firebase_crashlytics (3.4.14): + - Firebase/Crashlytics (= 10.20.0) + - firebase_core + - Flutter + - FirebaseAnalytics (10.20.0): + - FirebaseAnalytics/AdIdSupport (= 10.20.0) + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseAnalytics/AdIdSupport (10.20.0): + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleAppMeasurement (= 10.20.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseCore (10.20.0): + - FirebaseCoreInternal (~> 10.0) + - GoogleUtilities/Environment (~> 7.12) + - GoogleUtilities/Logger (~> 7.12) + - FirebaseCoreExtension (10.21.0): + - FirebaseCore (~> 10.0) + - FirebaseCoreInternal (10.21.0): + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseCrashlytics (10.20.0): + - FirebaseCore (~> 10.5) + - FirebaseInstallations (~> 10.0) + - FirebaseSessions (~> 10.5) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.8) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesObjC (~> 2.1) + - FirebaseInstallations (10.21.0): + - FirebaseCore (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/UserDefaults (~> 7.8) + - PromisesObjC (~> 2.1) + - FirebaseSessions (10.21.0): + - FirebaseCore (~> 10.5) + - FirebaseCoreExtension (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.10) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesSwift (~> 2.1) - Flutter (1.0.0) - flutter_downloader (0.0.1): - Flutter @@ -68,6 +136,49 @@ PODS: - GCDWebServer (3.5.4): - GCDWebServer/Core (= 3.5.4) - GCDWebServer/Core (3.5.4) + - GoogleAppMeasurement (10.20.0): + - GoogleAppMeasurement/AdIdSupport (= 10.20.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleAppMeasurement/AdIdSupport (10.20.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 10.20.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleAppMeasurement/WithoutAdIdSupport (10.20.0): + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleDataTransport (9.3.0): + - GoogleUtilities/Environment (~> 7.7) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/AppDelegateSwizzler (7.12.0): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.12.0): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.12.0): + - GoogleUtilities/Environment + - GoogleUtilities/MethodSwizzler (7.12.0): + - GoogleUtilities/Logger + - GoogleUtilities/Network (7.12.0): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.12.0)" + - GoogleUtilities/Reachability (7.12.0): + - GoogleUtilities/Logger + - GoogleUtilities/UserDefaults (7.12.0): + - GoogleUtilities/Logger - HLSCachingReverseProxyServer (0.1.0): - GCDWebServer (~> 3.5) - PINCache (>= 3.0.1-beta.3) @@ -90,6 +201,11 @@ PODS: - libwebp/sharpyuv (1.3.2) - libwebp/webp (1.3.2): - libwebp/sharpyuv + - nanopb (2.30909.1): + - nanopb/decode (= 2.30909.1) + - nanopb/encode (= 2.30909.1) + - nanopb/decode (2.30909.1) + - nanopb/encode (2.30909.1) - package_info_plus (0.4.5): - Flutter - path_provider_foundation (0.0.1): @@ -105,6 +221,9 @@ PODS: - PINCache/Core (3.0.3): - PINOperation (~> 1.2.1) - PINOperation (1.2.2) + - PromisesObjC (2.3.1) + - PromisesSwift (2.3.1): + - PromisesObjC (= 2.3.1) - SDWebImage (5.18.10): - SDWebImage/Core (= 5.18.10) - SDWebImage/Core (5.18.10) @@ -152,6 +271,9 @@ DEPENDENCIES: - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - ffmpeg_kit_flutter (from `.symlinks/plugins/ffmpeg_kit_flutter/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) + - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`) - Flutter (from `Flutter`) - flutter_downloader (from `.symlinks/plugins/flutter_downloader/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) @@ -179,12 +301,26 @@ SPEC REPOS: - DKImagePickerController - DKPhotoGallery - ffmpeg-kit-ios-https + - Firebase + - FirebaseAnalytics + - FirebaseCore + - FirebaseCoreExtension + - FirebaseCoreInternal + - FirebaseCrashlytics + - FirebaseInstallations + - FirebaseSessions - FYVideoCompressor - GCDWebServer + - GoogleAppMeasurement + - GoogleDataTransport + - GoogleUtilities - HLSCachingReverseProxyServer - libwebp + - nanopb - PINCache - PINOperation + - PromisesObjC + - PromisesSwift - SDWebImage - Sentry - SentryPrivate @@ -210,6 +346,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/ffmpeg_kit_flutter/ios" file_picker: :path: ".symlinks/plugins/file_picker/ios" + firebase_analytics: + :path: ".symlinks/plugins/firebase_analytics/ios" + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_crashlytics: + :path: ".symlinks/plugins/firebase_crashlytics/ios" Flutter: :path: Flutter flutter_downloader: @@ -263,21 +405,38 @@ SPEC CHECKSUMS: ffmpeg-kit-ios-https: 8dffbe1623a2f227be98fc314294847a97f818e4 ffmpeg_kit_flutter: 17e9f35a4ec996ac55051c20be05240f2a0b53e8 file_picker: ce3938a0df3cc1ef404671531facef740d03f920 + Firebase: 10c8cb12fb7ad2ae0c09ffc86cd9c1ab392a0031 + firebase_analytics: 2e82fd84ce13f8321aa7b99336d6ee0e6cc7b984 + firebase_core: a46c312d8bae4defa3d009b2aa7b5b413aeb394e + firebase_crashlytics: 3d12285fcbd865d576b9965bd4090cd8b68e11fd + FirebaseAnalytics: a2731bf3670747ce8f65368b118d18aa8e368246 + FirebaseCore: 28045c1560a2600d284b9c45a904fe322dc890b6 + FirebaseCoreExtension: 1c044fd46e95036cccb29134757c499613f3f564 + FirebaseCoreInternal: 43c1788eaeee9d1b97caaa751af567ce11010d00 + FirebaseCrashlytics: 81530595edb6d99f1918f723a6c33766a24a4c86 + FirebaseInstallations: 390ea1d10a4d02b20c965cbfd527ee9b3b412acb + FirebaseSessions: 80c2bbdd28166267b3d132debe5f7531efdb00bc Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_downloader: b7301ae057deadd4b1650dc7c05375f10ff12c39 flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be FYVideoCompressor: 80e2a90bbc118044038b37b8442f23084c5698bf GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4 + GoogleAppMeasurement: bb3c564c3efb933136af0e94899e0a46167466a8 + GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe + GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34 HLSCachingReverseProxyServer: 59935e1e0244ad7f3375d75b5ef46e8eb26ab181 image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425 images_picker: fa9364e3a7d3083c49f865fcfb2b9e7cdc574d3a just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 + nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5 package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 PINOperation: daa34d4aa1d8449089be7d405b9d974abc4724c6 + PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 + PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265 SDWebImage: fc8f2d48bbfd72ef39d70e981bd24a3f3be53fec Sentry: 1ebcaef678a27c8ac515f974cb5425dd1bbdec2f sentry_flutter: ecdfbedee55337205561cfa782ee02d31ec83e1f @@ -296,4 +455,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: c47b194cb97680e602c9d704f278cff245139eb7 -COCOAPODS: 1.11.3 +COCOAPODS: 1.15.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 9987aeb8..b5d68bcc 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -203,6 +203,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 214AAB41E8D0416E47EF2909 /* [CP] Embed Pods Frameworks */, + E16D86D96B9AC4CC871B1E93 /* [firebase_crashlytics] Crashlytics Upload Symbols */, ); buildRules = ( ); @@ -333,6 +334,29 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + E16D86D96B9AC4CC871B1E93 /* [firebase_crashlytics] Crashlytics Upload Symbols */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}\"", + "\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/\"", + "\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"", + "\"$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)\"", + "\"$(PROJECT_DIR)/firebase_app_id_file.json\"", + ); + name = "[firebase_crashlytics] Crashlytics Upload Symbols"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$PODS_ROOT/FirebaseCrashlytics/upload-symbols\" --flutter-project \"$PROJECT_DIR/firebase_app_id_file.json\" "; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index 6730edbb..216a1df6 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -30,6 +30,7 @@ class HiveUserData { String union; bool loaded; String? accessToken; + bool authority; HiveUserData({ required this.username, diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index 769a186c..a840cd2b 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -30,8 +30,7 @@ class HiveAuthLoginScreen extends StatefulWidget { State createState() => _HiveAuthLoginScreenState(); } -class _HiveAuthLoginScreenState extends State - with TickerProviderStateMixin { +class _HiveAuthLoginScreenState extends State with TickerProviderStateMixin { static const platform = MethodChannel('blog.hive.auth/bridge'); var usernameController = TextEditingController(); late WebSocketChannel socket; @@ -68,12 +67,7 @@ class _HiveAuthLoginScreenState extends State break; case "auth_wait": var uuid = asString(map, 'uuid'); - var jsonData = { - "account": usernameController.text, - "uuid": uuid, - "key": authKey, - "host": Communicator.hiveAuthServer - }; + var jsonData = {"account": usernameController.text, "uuid": uuid, "key": authKey, "host": Communicator.hiveAuthServer}; var jsonString = json.encode(jsonData); var utf8Data = utf8.encode(jsonString); var qr = base64.encode(utf8Data); @@ -130,10 +124,11 @@ class _HiveAuthLoginScreenState extends State }); break; case "sign_ack": - performSignInWithHAS(); + performSignInWithHAS(true); break; case "sign_nack": - showError("You denied granting posting authority to 3Speak"); + showError("3Speak does not have posting authority to your account. You can not publish videos"); + performSignInWithHAS(false); break; default: log('Default case here'); @@ -276,18 +271,15 @@ class _HiveAuthLoginScreenState extends State ? Column( children: [ const SizedBox(height: 10), - const Text( - 'Authorize this request with "Keychain for Hive" app.'), + const Text('Authorize this request with "Keychain for Hive" app.'), const SizedBox(height: 20), ElevatedButton( onPressed: () { var url = Uri.parse(qr); launchUrl(url); }, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black), - child: Image.asset('assets/hive-keychain-image.png', - width: 220), + style: ElevatedButton.styleFrom(backgroundColor: Colors.black), + child: Image.asset('assets/hive-keychain-image.png', width: 220), ), const SizedBox(height: 20), SizedBox(height: 10), @@ -326,8 +318,7 @@ class _HiveAuthLoginScreenState extends State onPressed: () { onLoginTapped(appData); }, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black), + style: ElevatedButton.styleFrom(backgroundColor: Colors.black), child: const Text('Login with Posting Key'), ), const SizedBox(height: 10), @@ -340,8 +331,7 @@ class _HiveAuthLoginScreenState extends State Navigator.of(context).push(route); }, child: Text('Sign up'), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black), + style: ElevatedButton.styleFrom(backgroundColor: Colors.black), ), ], ), @@ -365,8 +355,7 @@ class _HiveAuthLoginScreenState extends State }); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); if (bridgeResponse.valid) { - final String doWeHave = - await MethodChannel("blog.hive.auth/bridge").invokeMethod( + final String doWeHave = await MethodChannel("blog.hive.auth/bridge").invokeMethod( 'doWeHavePostingAuth', { 'username': usernameController.text, @@ -374,80 +363,65 @@ class _HiveAuthLoginScreenState extends State ); var doWeHaveResponse = LoginBridgeResponse.fromJsonString(doWeHave); if (doWeHaveResponse.valid) { - if (doWeHaveResponse.data != null && - doWeHaveResponse.data == "true") { - // we have posting authority. we can login now. - String proofPayload = json.encode({ - 'account': usernameController.text, - 'ts': DateTime.now().toIso8601String() - }); - const platform = MethodChannel('com.example.acela/auth'); - final String result = - await platform.invokeMethod('getProofOfPayload', { - 'username': usernameController.text, - 'postingKey': postingKey, - 'proof': proofPayload, - }); - LoginBridgeResponse actionResponse = LoginBridgeResponse.fromJsonString(result); - if (actionResponse.valid && - actionResponse.error == '' && - actionResponse.data != null && actionResponse.data!.isNotEmpty) { - var loginApiResponse = await Communicator().login( - usernameController.text, proofPayload, actionResponse.data!); - if (loginApiResponse.valid) { - debugPrint("Successful login"); - String resolution = - await storage.read(key: 'resolution') ?? '480p'; - String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - String union = await storage.read(key: 'union') ?? - GQLCommunicator.defaultGQLServer; - String? lang = await storage.read(key: 'lang'); - await storage.write( - key: 'username', value: usernameController.text); - await storage.write(key: 'postingKey', value: postingKey); - await storage.write(key: 'accessToken', value: loginApiResponse.data); - await storage.delete(key: 'hasId'); - await storage.delete(key: 'hasExpiry'); - await storage.delete(key: 'hasAuthKey'); - await storage.delete(key: 'cookie'); - var data = HiveUserData( - username: usernameController.text, - postingKey: postingKey, - keychainData: null, - accessToken: loginApiResponse.data, - resolution: resolution, - rpc: rpc, - union: union, - loaded: true, - language: lang, - ); - server.updateHiveUserData(data); - Navigator.of(context).pop(); - var screen = GQLFeedScreen( - appData: data, - username: usernameController.text, - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).pushReplacement(route); - showMessage( - 'You have successfully logged in as - ${usernameController.text}'); - setState(() { - isLoading = false; - }); - } else { - showError(loginApiResponse.error); - setState(() { - isLoading = false; - }); - } + var authority = doWeHaveResponse.data != null && doWeHaveResponse.data != "true"; + if (authority) { + showError("3Speak does not have posting authority to your account. You can not publish videos"); + } + await storage.write(key: 'postingAuth', value: "${authority ? 'true' : 'false'}"); + String proofPayload = json.encode({'account': usernameController.text, 'ts': DateTime.now().toIso8601String()}); + const platform = MethodChannel('com.example.acela/auth'); + final String result = await platform.invokeMethod('getProofOfPayload', { + 'username': usernameController.text, + 'postingKey': postingKey, + 'proof': proofPayload, + }); + LoginBridgeResponse actionResponse = LoginBridgeResponse.fromJsonString(result); + if (actionResponse.valid && actionResponse.error == '' && actionResponse.data != null && actionResponse.data!.isNotEmpty) { + var loginApiResponse = await Communicator().login(usernameController.text, proofPayload, actionResponse.data!); + if (loginApiResponse.valid) { + debugPrint("Successful login"); + String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + String union = await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; + String? lang = await storage.read(key: 'lang'); + await storage.write(key: 'username', value: usernameController.text); + await storage.write(key: 'postingKey', value: postingKey); + await storage.write(key: 'accessToken', value: loginApiResponse.data); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); + await storage.delete(key: 'cookie'); + var data = HiveUserData( + username: usernameController.text, + postingKey: postingKey, + keychainData: null, + accessToken: loginApiResponse.data, + resolution: resolution, + rpc: rpc, + union: union, + loaded: true, + language: lang, + ); + server.updateHiveUserData(data); + Navigator.of(context).pop(); + var screen = GQLFeedScreen( + appData: data, + username: usernameController.text, + ); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).pushReplacement(route); + showMessage('You have successfully logged in as - ${usernameController.text}'); + setState(() { + isLoading = false; + }); } else { - showError(actionResponse.error); + showError(loginApiResponse.error); setState(() { isLoading = false; }); } } else { - showError(doWeHaveResponse.error); + showError(actionResponse.error); setState(() { isLoading = false; }); @@ -470,8 +444,7 @@ class _HiveAuthLoginScreenState extends State isLoading = false; }); log(e.toString()); - if (e == - 'No 3Speak Account found with name - ${usernameController.text}') { + if (e == 'No 3Speak Account found with name - ${usernameController.text}') { await storage.delete(key: 'username'); await storage.delete(key: 'postingKey'); await storage.delete(key: 'hasId'); @@ -502,31 +475,23 @@ class _HiveAuthLoginScreenState extends State } void decryptChallenge(HiveUserData data, String encryptedData) async { - final String response = - await platform.invokeMethod('getDecryptedChallenge', { + final String response = await platform.invokeMethod('getDecryptedChallenge', { 'username': usernameController.text, 'authKey': authKey, 'data': encryptedData, }); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); - if (bridgeResponse.valid && - bridgeResponse.data != null && - bridgeResponse.data!.isNotEmpty) { - var proof = bridgeResponse.data; - var payload = proofOfPayload; + if (bridgeResponse.valid && bridgeResponse.data != null && bridgeResponse.data!.isNotEmpty) { setState(() { signedHash = bridgeResponse.data!; }); - final String postingAuthResponse = - await platform.invokeMethod('getPostingAuthOps', { + final String postingAuthResponse = await platform.invokeMethod('getPostingAuthOps', { 'username': usernameController.text, 'authKey': authKey, }); - var postingAuthBridgeResponse = - LoginBridgeResponse.fromJsonString(postingAuthResponse); + var postingAuthBridgeResponse = LoginBridgeResponse.fromJsonString(postingAuthResponse); if (postingAuthBridgeResponse.valid) { - if (postingAuthBridgeResponse.data != null && - postingAuthBridgeResponse.data!.isNotEmpty) { + if (postingAuthBridgeResponse.data != null && postingAuthBridgeResponse.data!.isNotEmpty) { // get posting authority here. var socketData = { "cmd": "sign_req", @@ -537,38 +502,29 @@ class _HiveAuthLoginScreenState extends State var jsonEncodedData = json.encode(socketData); socket.sink.add(jsonEncodedData); } else { - performSignInWithHAS(); + performSignInWithHAS(true); } } else { - showMessage( - 'Error getting posting authority details. Please try again.'); + showMessage('Error getting posting authority details. Please try again.'); } } else { - showMessage( - 'Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); + showMessage('Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); } } - void performSignInWithHAS() async { + void performSignInWithHAS(bool authority) async { debugPrint("Signed proof is $signedHash"); debugPrint("Proof of Payload is $proofOfPayload"); debugPrint("Username is ${usernameController.text}"); - var loginApiResponse = await Communicator().login( - usernameController.text, proofOfPayload, signedHash); - String resolution = - await storage.read(key: 'resolution') ?? '480p'; + var loginApiResponse = await Communicator().login(usernameController.text, proofOfPayload, signedHash); + String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - String union = await storage.read(key: 'union') ?? - GQLCommunicator.defaultGQLServer; + String union = await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; String? lang = await storage.read(key: 'lang'); - await storage.write( - key: 'username', value: usernameController.text); + await storage.write(key: 'username', value: usernameController.text); await storage.delete(key: 'postingKey'); await storage.write(key: 'accessToken', value: loginApiResponse.data); - await storage.delete(key: 'hasId'); - await storage.delete(key: 'hasExpiry'); - await storage.delete(key: 'hasAuthKey'); - await storage.delete(key: 'cookie'); + await storage.write(key: 'postingAuth', value: "${authority ? 'true' : 'false'}"); var data = HiveUserData( username: usernameController.text, postingKey: null, @@ -588,28 +544,23 @@ class _HiveAuthLoginScreenState extends State ); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).pushReplacement(route); - showMessage( - 'You have successfully logged in as - ${usernameController.text}'); + showMessage('You have successfully logged in as - ${usernameController.text}'); setState(() { isLoading = false; }); } void decryptData(HiveUserData data, String encryptedData) async { - final String response = - await platform.invokeMethod('getDecryptedHASToken', { + final String response = await platform.invokeMethod('getDecryptedHASToken', { 'username': usernameController.text, 'authKey': authKey, 'data': encryptedData, }); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); - if (bridgeResponse.valid && - bridgeResponse.data != null && - bridgeResponse.data!.isNotEmpty) { + if (bridgeResponse.valid && bridgeResponse.data != null && bridgeResponse.data!.isNotEmpty) { var tokenData = bridgeResponse.data!.split(","); if (tokenData.isEmpty || tokenData.length != 2) { - showMessage( - 'Did not find token & expiry details from HiveAuth. Please go back & try again.'); + showMessage('Did not find token & expiry details from HiveAuth. Please go back & try again.'); } else { const storage = FlutterSecureStorage(); await storage.write(key: 'username', value: usernameController.text); @@ -634,15 +585,12 @@ class _HiveAuthLoginScreenState extends State language: data.language, ); server.updateHiveUserData(newData); - showMessage( - 'You have successfully logged in with Hive Auth with user - ${usernameController.text}'); - final String eChallengeResponse = - await platform.invokeMethod('getEncryptedChallenge', { + showMessage('You have successfully logged in with Hive Auth with user - ${usernameController.text}'); + final String eChallengeResponse = await platform.invokeMethod('getEncryptedChallenge', { 'username': usernameController.text, 'authKey': authKey, }); - var eChallengeResponseData = - json.decode(eChallengeResponse)['data'] as String; + var eChallengeResponseData = json.decode(eChallengeResponse)['data'] as String; var eData = eChallengeResponseData.split("|")[0]; setState(() { hasIdToken = tokenData[0]; @@ -665,8 +613,7 @@ class _HiveAuthLoginScreenState extends State // Navigator.of(context).pushReplacement(route); } } else { - showMessage( - 'Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); + showMessage('Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); } } diff --git a/lib/src/screens/video_details_screen/hive_upvote_dialog.dart b/lib/src/screens/video_details_screen/hive_upvote_dialog.dart index 59900083..f5014a73 100644 --- a/lib/src/screens/video_details_screen/hive_upvote_dialog.dart +++ b/lib/src/screens/video_details_screen/hive_upvote_dialog.dart @@ -241,7 +241,7 @@ class _HiveUpvoteDialogState extends State { var voteValue = sliderValue * 10000; var user = data.username; if (user == null) return; - if (widget.accessToken != null) { + if (widget.accessToken != null && widget.postingAuth) { // TO-DO: Call Acela-Core upvote API using access token. } else { try { diff --git a/pubspec.lock b/pubspec.lock index 11aac35c..310e42f1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1619,10 +1619,10 @@ packages: dependency: transitive description: name: video_player_android - sha256: "7f8f25d7ad56819a82b2948357f3c3af071f6a678db33833b26ec36bbc221316" + sha256: "4dd9b8b86d70d65eecf3dcabfcdfbb9c9115d244d022654aba49a00336d540c2" url: "https://pub.dev" source: hosted - version: "2.4.11" + version: "2.4.12" video_player_avfoundation: dependency: transitive description: From dec00f2430148038be9e65a0e0d79fa0860b7347 Mon Sep 17 00:00:00 2001 From: sagar Date: Thu, 15 Feb 2024 16:40:38 +0530 Subject: [PATCH 374/466] podcast video player, acela core api for upvote, download progress for podcast download --- lib/main.dart | 3 + lib/src/models/podcast/podcast_episodes.dart | 58 +++--- .../models/user_stream/hive_user_stream.dart | 30 ++-- .../home_screen/video_upload_sheet.dart | 1 + lib/src/screens/login/ha_login_screen.dart | 12 +- .../account_settings_screen.dart | 1 + .../controller/podcast_controller.dart | 4 +- .../screens/podcast/view/podcasts_feed.dart | 4 +- .../audio_player_core_controls.dart | 167 +++++++++++++++--- .../new_pod_cast_epidose_player.dart | 100 ++++++++--- .../control_buttons.dart | 8 +- .../download_podcast_button.dart | 42 +++-- lib/src/screens/settings/settings_screen.dart | 8 + .../comment/comment_action_menu.dart | 1 + .../hive_upvote_dialog.dart | 29 ++- .../new_video_details_screen.dart | 1 + .../video_details_screen.dart | 1 + lib/src/utils/communicator.dart | 7 +- lib/src/widgets/story_player.dart | 1 + lib/src/widgets/upvote_button.dart | 1 + 20 files changed, 357 insertions(+), 122 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 65fabb04..6c705cdf 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -126,6 +126,7 @@ class _MyAppState extends State { accessToken: null, postingKey: null, username: null, + postingAuthority: null, rpc: 'api.hive.blog', union: GQLCommunicator.defaultGQLServer, loaded: false, @@ -159,6 +160,7 @@ class _MyAppState extends State { String? hasAuthKey = await storage.read(key: 'hasAuthKey'); String resolution = await storage.read(key: 'resolution') ?? '480p'; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + String? postingAuth = await storage.read(key: 'postingAuth') ; String union = await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; if (union == 'threespeak-union-graph-ql.sagarkothari88.one') { @@ -184,6 +186,7 @@ class _MyAppState extends State { ) : null, accessToken: accessToken, + postingAuthority: postingAuth, resolution: resolution, rpc: rpc, union: union, diff --git a/lib/src/models/podcast/podcast_episodes.dart b/lib/src/models/podcast/podcast_episodes.dart index d59290b2..80e99017 100644 --- a/lib/src/models/podcast/podcast_episodes.dart +++ b/lib/src/models/podcast/podcast_episodes.dart @@ -66,21 +66,22 @@ class PodcastEpisode { String? image; String? guid; String? chaptersUrl; + bool isAudio; - PodcastEpisode({ - this.id, - this.title, - this.link, - this.description, - this.datePublished, - this.datePublishedPretty, - this.enclosureUrl, - this.duration, - this.episode, - this.image, - this.guid, - this.chaptersUrl - }); + PodcastEpisode( + {this.id, + this.title, + this.link, + this.description, + this.datePublished, + this.datePublishedPretty, + this.enclosureUrl, + this.duration, + this.episode, + this.image, + this.guid, + this.chaptersUrl, + required this.isAudio}); factory PodcastEpisode.fromRawJson(String str) => PodcastEpisode.fromJson(json.decode(str)); @@ -88,22 +89,23 @@ class PodcastEpisode { String toRawJson() => json.encode(toJson()); factory PodcastEpisode.fromJson(Map json) => PodcastEpisode( - id: json["id"].toString(), - title: json["title"], - link: json["link"], - description: json["description"], - datePublished: json["datePublished"], - datePublishedPretty: json["datePublishedPretty"], - enclosureUrl: json["enclosureUrl"], - duration: json["duration"], - episode: json["episode"], - image: json["image"], - guid: json["guid"], - chaptersUrl: json['chaptersUrl'] - ); + id: json["id"].toString(), + isAudio: json['enclosureType']?.contains('audio') ?? true, + title: json["title"], + link: json["link"], + description: json["description"], + datePublished: json["datePublished"], + datePublishedPretty: json["datePublishedPretty"], + enclosureUrl: json["enclosureUrl"], + duration: json["duration"], + episode: json["episode"], + image: json["image"], + guid: json["guid"], + chaptersUrl: json['chaptersUrl']); factory PodcastEpisode.fromRss(RssItem rssItem) => PodcastEpisode( id: rssItem.guid, + isAudio: rssItem.enclosure?.type?.contains('audio') ?? true, title: rssItem.title, link: rssItem.link, description: rssItem.description, @@ -127,6 +129,6 @@ class PodcastEpisode { "duration": duration, "episode": episode, "image": image, - 'chaptersUrl':chaptersUrl + 'chaptersUrl': chaptersUrl }; } diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index 216a1df6..5fbf02e3 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -30,17 +30,23 @@ class HiveUserData { String union; bool loaded; String? accessToken; - bool authority; + late bool postingAuthority; - HiveUserData({ - required this.username, - required this.postingKey, - required this.keychainData, - required this.accessToken, - required this.resolution, - required this.rpc, - required this.union, - required this.loaded, - required this.language, - }); + HiveUserData( + {required this.username, + required this.postingKey, + required this.keychainData, + required this.accessToken, + required this.resolution, + required this.rpc, + required this.union, + required this.loaded, + required this.language, + required String? postingAuthority,}) { + if (postingAuthority != null) { + this.postingAuthority = postingAuthority == 'true'; + } else { + this.postingAuthority = false; + } + } } diff --git a/lib/src/screens/home_screen/video_upload_sheet.dart b/lib/src/screens/home_screen/video_upload_sheet.dart index a2323a6d..7233dbc0 100644 --- a/lib/src/screens/home_screen/video_upload_sheet.dart +++ b/lib/src/screens/home_screen/video_upload_sheet.dart @@ -101,6 +101,7 @@ class VideoUploadSheet { postingKey: null, keychainData: null, accessToken: null, + postingAuthority: null, resolution: resolution, rpc: rpc, union: union, diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index a840cd2b..ff4563ea 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -363,11 +363,11 @@ class _HiveAuthLoginScreenState extends State with TickerPr ); var doWeHaveResponse = LoginBridgeResponse.fromJsonString(doWeHave); if (doWeHaveResponse.valid) { - var authority = doWeHaveResponse.data != null && doWeHaveResponse.data != "true"; - if (authority) { + var authority = doWeHaveResponse.data != null && doWeHaveResponse.data == "true"; + if (!authority) { showError("3Speak does not have posting authority to your account. You can not publish videos"); } - await storage.write(key: 'postingAuth', value: "${authority ? 'true' : 'false'}"); + await storage.write(key: 'postingAuth', value: authority.toString()); String proofPayload = json.encode({'account': usernameController.text, 'ts': DateTime.now().toIso8601String()}); const platform = MethodChannel('com.example.acela/auth'); final String result = await platform.invokeMethod('getProofOfPayload', { @@ -396,6 +396,7 @@ class _HiveAuthLoginScreenState extends State with TickerPr postingKey: postingKey, keychainData: null, accessToken: loginApiResponse.data, + postingAuthority: authority.toString(), resolution: resolution, rpc: rpc, union: union, @@ -456,6 +457,7 @@ class _HiveAuthLoginScreenState extends State with TickerPr postingKey: null, keychainData: null, accessToken: null, + postingAuthority: null, resolution: '480p', rpc: 'api.hive.blog', union: GQLCommunicator.defaultGQLServer, @@ -524,12 +526,13 @@ class _HiveAuthLoginScreenState extends State with TickerPr await storage.write(key: 'username', value: usernameController.text); await storage.delete(key: 'postingKey'); await storage.write(key: 'accessToken', value: loginApiResponse.data); - await storage.write(key: 'postingAuth', value: "${authority ? 'true' : 'false'}"); + await storage.write(key: 'postingAuth', value:authority.toString()); var data = HiveUserData( username: usernameController.text, postingKey: null, keychainData: null, accessToken: loginApiResponse.data, + postingAuthority: authority.toString(), resolution: resolution, rpc: rpc, union: union, @@ -578,6 +581,7 @@ class _HiveAuthLoginScreenState extends State with TickerPr hasId: tokenData[0], ), accessToken: null, + postingAuthority: null, resolution: data.resolution, rpc: data.rpc, union: data.union, diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index 6532fca1..5655fbd2 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -36,6 +36,7 @@ class _AccountSettingsScreenState extends State { postingKey: null, keychainData: null, accessToken: null, + postingAuthority: null, resolution: resolution, rpc: rpc, union: union, diff --git a/lib/src/screens/podcast/controller/podcast_controller.dart b/lib/src/screens/podcast/controller/podcast_controller.dart index e668452a..34d759e4 100644 --- a/lib/src/screens/podcast/controller/podcast_controller.dart +++ b/lib/src/screens/podcast/controller/podcast_controller.dart @@ -54,9 +54,9 @@ class PodcastController extends ChangeNotifier { return ""; } - String decodeAudioName(String name, {String? episodeId}) { + String decodeAudioName(String name, {String? episodeId,bool isAudio = true}) { String decodedName = name.split('/').last; - String target = ".mp3"; + String target = isAudio ? ".mp3" : ".mp4"; int index = decodedName.indexOf(target); if (index != -1) { decodedName = decodedName.substring(0, index + target.length); diff --git a/lib/src/screens/podcast/view/podcasts_feed.dart b/lib/src/screens/podcast/view/podcasts_feed.dart index e1819d87..7a733323 100644 --- a/lib/src/screens/podcast/view/podcasts_feed.dart +++ b/lib/src/screens/podcast/view/podcasts_feed.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:acela/src/models/podcast/podcast_episodes.dart'; import 'package:acela/src/models/podcast/trending_podcast_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; @@ -30,7 +32,7 @@ class _PodcastFeedScreenState extends State { @override void initState() { super.initState(); - future =loadPodCastEpisode(); + future = loadPodCastEpisode(); } Widget _fullPost(List items) { diff --git a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart index 6af3b4a9..b13edcb8 100644 --- a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart +++ b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart @@ -1,20 +1,21 @@ import 'dart:async'; import 'package:audio_service/audio_service.dart'; import 'package:audio_session/audio_session.dart'; +import 'package:dart_rss/domain/media/media.dart'; import 'package:just_audio/just_audio.dart'; import 'package:rxdart/rxdart.dart'; +import 'package:video_player/video_player.dart'; class GetAudioPlayer { GetAudioPlayer._(); late AudioPlayerHandler audioHandler; - + static final GetAudioPlayer _instance = GetAudioPlayer._(); factory GetAudioPlayer() { return _instance; } - } class QueueState { @@ -48,6 +49,16 @@ abstract class AudioPlayerHandler implements AudioHandler { ValueStream get volume; Future setVolume(double volume); ValueStream get speed; + + VideoPlayerController? videoPlayerController; + + void setUpVideoController(String url,); + + void disposeVideoController(); + + bool isVideo = false; + + bool shouldPlayVideo(); } /// The implementation of [AudioPlayerHandler]. @@ -69,6 +80,41 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler @override final BehaviorSubject speed = BehaviorSubject.seeded(1.0); final _mediaItemExpando = Expando(); + bool isVideo = false; + + VideoPlayerController? videoPlayerController; + + @override + bool shouldPlayVideo() { + return isVideo && videoPlayerController != null; + } + + void setUpVideoController(String url,) { + disposeVideoController(); + if (url.startsWith("http")) { + this.videoPlayerController = VideoPlayerController.networkUrl( + Uri.parse(url), + videoPlayerOptions: VideoPlayerOptions(allowBackgroundPlayback: true)) + ..initialize(); + } else { + this.videoPlayerController = VideoPlayerController.asset(url, + videoPlayerOptions: VideoPlayerOptions(allowBackgroundPlayback: true)) + ..initialize(); + } + videoPlayerController!.addListener(() { + _broadcastState(_player.playbackEvent); + }); + } + + void disposeVideoController() { + if (videoPlayerController != null) { + videoPlayerController!.seekTo(Duration.zero); + videoPlayerController!.removeListener(() { + _broadcastState(_player.playbackEvent); + }); + videoPlayerController!.dispose(); + } + } /// A stream of the current effective sequence from just_audio. Stream> get _effectiveSequence => Rx.combineLatest3< @@ -214,7 +260,6 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler } } - @override Future addQueueItem(MediaItem mediaItem) async { await _playlist.add(_itemToSource(mediaItem)); @@ -254,14 +299,21 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler } @override - Future skipToNext() => _player.seekToNext(); + Future skipToNext() async { + disposeVideoController(); + _player.seekToNext(); + } @override - Future skipToPrevious() => _player.seekToPrevious(); + Future skipToPrevious() async { + disposeVideoController(); + _player.seekToPrevious(); + } @override Future skipToQueueItem(int index) async { if (index < 0 || index >= _playlist.children.length) return; + disposeVideoController(); // This jumps to the beginning of the queue item at [index]. _player.seek(Duration.zero, index: _player.shuffleModeEnabled @@ -270,13 +322,17 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler } @override - Future play() => _player.play(); + Future play() => + shouldPlayVideo() ? videoPlayerController!.play() : _player.play(); @override - Future pause() => _player.pause(); + Future pause() => + shouldPlayVideo() ? videoPlayerController!.pause() : _player.pause(); @override - Future seek(Duration position) => _player.seek(position); + Future seek(Duration position) => shouldPlayVideo() + ? videoPlayerController!.seekTo(position) + : _player.seek(position); @override Future stop() async { @@ -285,17 +341,66 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler (state) => state.processingState == AudioProcessingState.idle); } + bool _isPlaying() => videoPlayerController?.value.isPlaying ?? false; + + AudioProcessingState _processingState() { + if (videoPlayerController == null) + return AudioProcessingState.loading; + else if (videoPlayerController!.value.isPlaying) + return AudioProcessingState.ready; + else if (videoPlayerController!.value.isBuffering) + return AudioProcessingState.loading; + else if (videoPlayerController!.value.isInitialized) + return AudioProcessingState.idle; + return AudioProcessingState.loading; + } + + Duration _bufferedPosition() { + if (videoPlayerController != null) { + DurationRange? currentBufferedRange = + (videoPlayerController!.value.buffered.isEmpty) + ? null + : (videoPlayerController?.value.buffered.firstWhere( + (durationRange) { + Duration position = videoPlayerController!.value.position; + bool isCurrentBufferedRange = + durationRange.start < position && + durationRange.end > position; + return isCurrentBufferedRange; + }, + orElse: () => DurationRange( + videoPlayerController!.value.position, + videoPlayerController!.value.position), + )); + if (currentBufferedRange == null) return Duration.zero; + return currentBufferedRange.end; + } else { + return Duration.zero; + } + } + /// Broadcasts the current state to all clients. void _broadcastState(PlaybackEvent event) { final playing = _player.playing; + + List controls = []; + controls.add( + MediaControl.skipToPrevious, + ); + if (shouldPlayVideo()) { + controls.add((_isPlaying()) ? MediaControl.pause : MediaControl.play); + } else { + controls.add( + (playing) ? MediaControl.pause : MediaControl.play, + ); + } + controls.add( + MediaControl.skipToNext, + ); final queueIndex = getQueueIndex( event.currentIndex, _player.shuffleModeEnabled, _player.shuffleIndices); playbackState.add(playbackState.value.copyWith( - controls: [ - MediaControl.skipToPrevious, - if (playing) MediaControl.pause else MediaControl.play, - MediaControl.skipToNext, - ], + controls: controls, systemActions: const { MediaAction.seek, MediaAction.seekForward, @@ -306,22 +411,31 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler MediaAction.skipToPrevious }, androidCompactActionIndices: const [0, 1, 3], - processingState: const { - ProcessingState.idle: AudioProcessingState.idle, - ProcessingState.loading: AudioProcessingState.loading, - ProcessingState.buffering: AudioProcessingState.buffering, - ProcessingState.ready: AudioProcessingState.ready, - ProcessingState.completed: AudioProcessingState.completed, - }[_player.processingState]!, - playing: playing, - updatePosition: _player.position, - bufferedPosition: _player.bufferedPosition, - speed: _player.speed, + processingState: shouldPlayVideo() + ? _processingState() + : const { + ProcessingState.idle: AudioProcessingState.idle, + ProcessingState.loading: AudioProcessingState.loading, + ProcessingState.buffering: AudioProcessingState.buffering, + ProcessingState.ready: AudioProcessingState.ready, + ProcessingState.completed: AudioProcessingState.completed, + }[_player.processingState]!, + playing: shouldPlayVideo() ? _isPlaying() : playing, + updatePosition: shouldPlayVideo() + ? videoPlayerController?.value.position ?? Duration.zero + : _player.position, + bufferedPosition: + shouldPlayVideo() ? _bufferedPosition() : _player.bufferedPosition, + speed: shouldPlayVideo() + ? videoPlayerController?.value.playbackSpeed ?? 1.0 + : _player.speed, queueIndex: queueIndex, )); } } +// disposeStream + /// Provides access to a library of media items. In your app, this could come /// from a database or web service. class MediaLibrary { @@ -335,7 +449,6 @@ class MediaLibrary { playable: false, ), ], - albumsRootId: [ - ], + albumsRootId: [], }; -} \ No newline at end of file +} diff --git a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart index 60a86ed6..5810e312 100644 --- a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart +++ b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'package:acela/src/models/podcast/podcast_episode_chapters.dart'; import 'package:acela/src/models/podcast/podcast_episodes.dart'; import 'package:acela/src/screens/podcast/controller/podcast_chapters_controller.dart'; @@ -16,14 +17,17 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:video_player/video_player.dart'; class NewPodcastEpidosePlayer extends StatefulWidget { - const NewPodcastEpidosePlayer({Key? key, required this.podcastEpisodes}) : super(key: key); + const NewPodcastEpidosePlayer({Key? key, required this.podcastEpisodes}) + : super(key: key); final List podcastEpisodes; @override - State createState() => _NewPodcastEpidosePlayerState(); + State createState() => + _NewPodcastEpidosePlayerState(); } class _NewPodcastEpidosePlayerState extends State { @@ -38,24 +42,35 @@ class _NewPodcastEpidosePlayerState extends State { late String originalTitle; late String? originalImage; - Stream get _bufferedPositionStream => _audioHandler.playbackState.map((state) => state.bufferedPosition).distinct(); + Stream get _bufferedPositionStream => _audioHandler.playbackState + .map((state) => state.bufferedPosition) + .distinct(); - Stream get _durationStream => _audioHandler.mediaItem.map((item) => item?.duration).distinct(); + Stream get _durationStream => + _audioHandler.mediaItem.map((item) => item?.duration).distinct(); - Stream get _positionDataStream => Rx.combineLatest3(AudioService.position, _bufferedPositionStream, - _durationStream, (position, bufferedPosition, duration) => PositionData(position, bufferedPosition, duration ?? Duration.zero)); + Stream get _positionDataStream => + Rx.combineLatest3( + AudioService.position, + _bufferedPositionStream, + _durationStream, + (position, bufferedPosition, duration) => PositionData( + position, bufferedPosition, duration ?? Duration.zero)); @override void initState() { super.initState(); - podcastController = context.read(); currentPodcastEpisode = widget.podcastEpisodes[currentPodcastIndex]; + _setUpVideo(); + podcastController = context.read(); originalImage = currentPodcastEpisode.image; originalTitle = currentPodcastEpisode.title!; // TO-DO: Ram to handle chapters for offline player // if (currentPodcastEpisode.enclosureUrl != null && currentPodcastEpisode.enclosureUrl!.startsWith("http")) { - chapterController = PodcastChapterController( - chapterUrl: currentPodcastEpisode.chaptersUrl, totalDuration: currentPodcastEpisode.duration ?? 0, audioPlayerHandler: _audioHandler); + chapterController = PodcastChapterController( + chapterUrl: currentPodcastEpisode.chaptersUrl, + totalDuration: currentPodcastEpisode.duration ?? 0, + audioPlayerHandler: _audioHandler); // } queueSubscription = _audioHandler.queueState.listen((event) {}); queueSubscription.onData((data) { @@ -63,15 +78,29 @@ class _NewPodcastEpidosePlayerState extends State { }); } + void _setUpVideo() { + _audioHandler.disposeVideoController(); + log(currentPodcastEpisode.enclosureUrl!); + if (!currentPodcastEpisode.isAudio) { + _audioHandler.isVideo = true; + _audioHandler.setUpVideoController(currentPodcastEpisode.enclosureUrl!); + log('video'); + _audioHandler.isVideo = false; + } + } + void _onEpisodeChange(data) { QueueState queueState = data as QueueState; if (currentPodcastIndex != queueState.queueIndex) { setState(() { currentPodcastIndex = queueState.queueIndex ?? 0; currentPodcastEpisode = widget.podcastEpisodes[currentPodcastIndex]; + _setUpVideo(); // if (currentPodcastEpisode.enclosureUrl != null && currentPodcastEpisode.enclosureUrl!.startsWith("http")) { - chapterController = PodcastChapterController( - chapterUrl: currentPodcastEpisode.chaptersUrl, totalDuration: currentPodcastEpisode.duration ?? 0, audioPlayerHandler: _audioHandler); + chapterController = PodcastChapterController( + chapterUrl: currentPodcastEpisode.chaptersUrl, + totalDuration: currentPodcastEpisode.duration ?? 0, + audioPlayerHandler: _audioHandler); // } originalTitle = currentPodcastEpisode.title!; originalImage = currentPodcastEpisode.image; @@ -100,19 +129,28 @@ class _NewPodcastEpidosePlayerState extends State { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - Container( - constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.45), - child: Selector( - selector: (_, myType) => myType.image, - builder: (context, chapterImage, child) { - return CachedImage( - imageUrl: chapterImage ?? originalImage, - imageHeight: MediaQuery.of(context).size.height * 0.45, - ); - }, - )), + _audioHandler.shouldPlayVideo() + ? SizedBox( + height: MediaQuery.of(context).size.height * 0.45, + width: double.infinity, + child: VideoPlayer(_audioHandler.videoPlayerController!)) + : Container( + constraints: BoxConstraints( + maxHeight: + MediaQuery.of(context).size.height * 0.45), + child: Selector( + selector: (_, myType) => myType.image, + builder: (context, chapterImage, child) { + return CachedImage( + imageUrl: chapterImage ?? originalImage, + imageHeight: + MediaQuery.of(context).size.height * 0.45, + ); + }, + )), Padding( - padding: const EdgeInsets.symmetric(vertical: 15.0, horizontal: 10), + padding: const EdgeInsets.symmetric( + vertical: 15.0, horizontal: 10), child: Column( children: [ Selector( @@ -142,7 +180,8 @@ class _NewPodcastEpidosePlayerState extends State { chapterController: chapterController, audioPlayerHandler: _audioHandler, positionDataStream: _positionDataStream, - currentPodcastEpisodeDuration: currentPodcastEpisode.duration), + currentPodcastEpisodeDuration: + currentPodcastEpisode.duration), ControlButtons( _audioHandler, chapterController: chapterController, @@ -186,12 +225,15 @@ class _NewPodcastEpidosePlayerState extends State { toastType: "Podcast Episode", disablePadding: true, iconColor: iconColor, - isLiked: podcastController.isLikedPodcastEpisodePresentLocally(currentPodcastEpisode), + isLiked: podcastController + .isLikedPodcastEpisodePresentLocally(currentPodcastEpisode), onAdd: () { - podcastController.storeLikedPodcastEpisodeLocally(currentPodcastEpisode); + podcastController + .storeLikedPodcastEpisodeLocally(currentPodcastEpisode); }, onRemove: () { - podcastController.storeLikedPodcastEpisodeLocally(currentPodcastEpisode); + podcastController + .storeLikedPodcastEpisodeLocally(currentPodcastEpisode); }), IconButton( onPressed: () { @@ -234,7 +276,9 @@ class _NewPodcastEpidosePlayerState extends State { builder: (context) { return SizedBox( height: MediaQuery.of(context).size.height * 0.7, - child: PodcastInfoDescroption(title: currentPodcastEpisode.title, description: currentPodcastEpisode.description)); + child: PodcastInfoDescroption( + title: currentPodcastEpisode.title, + description: currentPodcastEpisode.description)); }, ); } diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart index c1a07397..95094971 100644 --- a/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart @@ -24,6 +24,7 @@ class ControlButtons extends StatelessWidget { @override Widget build(BuildContext context) { + bool isPaused = false; Color iconColor = Colors.white; return Row( mainAxisSize: MainAxisSize.min, @@ -70,7 +71,7 @@ class ControlButtons extends StatelessWidget { final playbackState = snapshot.data; final processingState = playbackState?.processingState; final playing = playbackState?.playing; - if (processingState == AudioProcessingState.idle) + if (processingState == AudioProcessingState.idle && !isPaused) audioHandler.play(); if (processingState == AudioProcessingState.loading || processingState == AudioProcessingState.buffering) { @@ -99,7 +100,10 @@ class ControlButtons extends StatelessWidget { ); } else { return GestureDetector( - onTap: audioHandler.pause, + onTap: () { + isPaused = !isPaused; + audioHandler.pause(); + }, child: CircleAvatar( backgroundColor: Colors.white, child: Icon( diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart index 1028fc44..592dd83f 100644 --- a/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart @@ -25,6 +25,7 @@ class DownloadPodcastButton extends StatefulWidget { class _DownloadPodcastButtonState extends State { late PodcastController podcastController; + final ValueNotifier downloadProgress = ValueNotifier(0); DownloadStatus status = DownloadStatus.download; ReceivePort _port = ReceivePort(); @@ -33,12 +34,14 @@ class _DownloadPodcastButtonState extends State { void initState() { super.initState(); podcastController = context.read(); - IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port'); + IsolateNameServer.registerPortWithName( + _port.sendPort, 'downloader_send_port'); _port.listen((dynamic data) { // String id = data[0]; // DownloadTaskStatus status = (data[1]); int progress = data[2]; - print(progress); + downloadProgress.value = progress.toDouble(); + print('progess is $progress'); if (data[1] == 0 || data[1] == 4 || data[1] == 5) { setState(() { status = DownloadStatus.download; @@ -64,7 +67,8 @@ class _DownloadPodcastButtonState extends State { }); } } - print(podcastController.isOffline(widget.episode.enclosureUrl ?? "", widget.episode.id.toString())); + print(podcastController.isOffline( + widget.episode.enclosureUrl ?? "", widget.episode.id.toString())); super.didUpdateWidget(oldWidget); } @@ -77,7 +81,8 @@ class _DownloadPodcastButtonState extends State { @pragma('vm:entry-point') static void downloadCallback(String id, int status, int progress) { - final SendPort? send = IsolateNameServer.lookupPortByName('downloader_send_port'); + final SendPort? send = + IsolateNameServer.lookupPortByName('downloader_send_port'); send!.send([id, status, progress]); } @@ -87,17 +92,26 @@ class _DownloadPodcastButtonState extends State { } Widget _build(BuildContext context) { + final theme = Theme.of(context); final iconColor = widget.color; if (status == DownloadStatus.downloading) { return SizedBox( - height: 17, - width: 17, - child: CircularProgressIndicator( - strokeWidth: 2, - color: iconColor, - ), + height: 20, + width: 20, + child: ValueListenableBuilder( + valueListenable: downloadProgress, + builder: (context, progress, child) { + return CircularProgressIndicator( + strokeWidth: 2, + value: progress / 100, + valueColor: AlwaysStoppedAnimation(iconColor), + backgroundColor: theme.primaryColorLight.withOpacity(0.4), + ); + }), ); - } else if (podcastController.isOffline(widget.episode.enclosureUrl ?? "", widget.episode.id.toString()) || status == DownloadStatus.downloaded) { + } else if (podcastController.isOffline( + widget.episode.enclosureUrl ?? "", widget.episode.id.toString()) || + status == DownloadStatus.downloaded) { return Icon( Icons.check, color: iconColor, @@ -107,7 +121,8 @@ class _DownloadPodcastButtonState extends State { icon: Icon(Icons.download, color: iconColor), onPressed: () { try { - download(widget.episode.enclosureUrl.toString(), podcastController.externalDir?.path ?? ""); + download(widget.episode.enclosureUrl.toString(), + podcastController.externalDir?.path ?? ""); } catch (e) { print("Error - ${e.toString()}"); setState(() { @@ -126,7 +141,8 @@ class _DownloadPodcastButtonState extends State { FlutterDownloader.enqueue( url: url, savedDir: savePath, - fileName: podcastController.decodeAudioName(widget.episode.enclosureUrl!, episodeId: widget.episode.id.toString()), + fileName: podcastController.decodeAudioName(widget.episode.enclosureUrl!, + episodeId: widget.episode.id.toString(),isAudio: widget.episode.isAudio), showNotification: true, openFileFromNotification: true, ); diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index 103461ad..abce0065 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -91,6 +91,7 @@ class _SettingsScreenState extends State { String? hasExpiry = await storage.read(key: 'hasExpiry'); String? hasAuthKey = await storage.read(key: 'hasAuthKey'); String? accessToken = await storage.read(key: 'accessToken'); + String? postingAuth = await storage.read(key: 'postingAuth') ; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; String union = await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; @@ -100,6 +101,7 @@ class _SettingsScreenState extends State { username: username, postingKey: postingKey, accessToken: accessToken, + postingAuthority: postingAuth, resolution: optionName, rpc: rpc, union: union, @@ -174,6 +176,7 @@ class _SettingsScreenState extends State { accessToken: appData.accessToken, resolution: appData.resolution, rpc: appData.rpc, + postingAuthority: appData.postingAuthority.toString() , union: appData.union, loaded: true, language: language.code == 'all' ? null : language.code, @@ -243,6 +246,8 @@ class _SettingsScreenState extends State { const storage = FlutterSecureStorage(); await storage.delete(key: 'username'); await storage.delete(key: 'postingKey'); + await storage.delete(key: 'accessToken'); + await storage.delete(key: 'postingAuth'); await storage.delete(key: 'cookie'); await storage.delete(key: 'hasId'); await storage.delete(key: 'hasExpiry'); @@ -257,6 +262,7 @@ class _SettingsScreenState extends State { postingKey: null, keychainData: null, accessToken: null, + postingAuthority: null, resolution: resolution, rpc: rpc, union: union, @@ -444,6 +450,7 @@ class _SettingsScreenState extends State { postingKey: user.postingKey, keychainData: user.keychainData, accessToken: user.accessToken, + postingAuthority: user.postingAuthority.toString(), resolution: user.resolution, union: user.union, rpc: serverUrl, @@ -517,6 +524,7 @@ class _SettingsScreenState extends State { postingKey: user.postingKey, keychainData: user.keychainData, accessToken: user.accessToken, + postingAuthority: user.postingAuthority.toString(), resolution: user.resolution, union: serverUrl, rpc: user.rpc, diff --git a/lib/src/screens/video_details_screen/comment/comment_action_menu.dart b/lib/src/screens/video_details_screen/comment/comment_action_menu.dart index 4179c3fa..465cdc48 100644 --- a/lib/src/screens/video_details_screen/comment/comment_action_menu.dart +++ b/lib/src/screens/video_details_screen/comment/comment_action_menu.dart @@ -59,6 +59,7 @@ class CommentActionMenu extends StatelessWidget { permlink: permlink, username: appData.username ?? "", accessToken: appData.accessToken, + postingAuthority: appData.postingAuthority, hasKey: appData.keychainData?.hasId ?? "", hasAuthKey: appData.keychainData?.hasAuthKey ?? "", activeVotes: [], diff --git a/lib/src/screens/video_details_screen/hive_upvote_dialog.dart b/lib/src/screens/video_details_screen/hive_upvote_dialog.dart index f5014a73..e2f12440 100644 --- a/lib/src/screens/video_details_screen/hive_upvote_dialog.dart +++ b/lib/src/screens/video_details_screen/hive_upvote_dialog.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; +import 'package:acela/src/models/action_response.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; @@ -24,6 +25,7 @@ class HiveUpvoteDialog extends StatefulWidget { required this.hasKey, required this.hasAuthKey, required this.accessToken, + required this.postingAuthority, required this.activeVotes, required this.onClose, required this.onDone, @@ -34,6 +36,7 @@ class HiveUpvoteDialog extends StatefulWidget { final String hasKey; final String hasAuthKey; final String? accessToken; + final bool postingAuthority; final Function onDone; final Function onClose; final List activeVotes; @@ -241,9 +244,29 @@ class _HiveUpvoteDialogState extends State { var voteValue = sliderValue * 10000; var user = data.username; if (user == null) return; - if (widget.accessToken != null && widget.postingAuth) { - // TO-DO: Call Acela-Core upvote API using access token. - } else { + if (widget.accessToken != null && widget.postingAuthority) { + ActionResponse response = await Communicator() + .vote(widget.accessToken!, widget.author, widget.permlink); + if (response.valid && response.error.isEmpty) { + // Future.delayed(const Duration(seconds: 6), () { + if (mounted) { + setState(() { + isUpVoting = false; + widget.onDone(); + Navigator.of(context).pop(); + }); + } + // }); + } else { + showError(response.error); + if (isUpVoting && mounted) { + setState(() { + isUpVoting = false; + }); + } + } + } + else { try { const platform = MethodChannel('com.example.acela/auth'); final String result = await platform.invokeMethod('voteContent', { diff --git a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart index 5d4c6f47..4505067d 100644 --- a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart +++ b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart @@ -482,6 +482,7 @@ class _NewVideoDetailsScreenState extends State { permlink: widget.item.permlink ?? 'ctbtwcxbbd', username: widget.appData.username ?? "", accessToken: widget.appData.accessToken, + postingAuthority: widget.appData.postingAuthority, hasKey: widget.appData.keychainData?.hasId ?? "", hasAuthKey: widget.appData.keychainData?.hasAuthKey ?? "", activeVotes: postInfo!.activeVotes, diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 34fc4177..4839202b 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -233,6 +233,7 @@ class _VideoDetailsScreenState extends State { permlink: widget.vm.permlink, username: appData.username ?? "", accessToken: appData.accessToken, + postingAuthority: appData.postingAuthority, hasKey: appData.keychainData?.hasId ?? "", hasAuthKey: appData.keychainData?.hasAuthKey ?? "", diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 8a8aeecb..d225d907 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -746,10 +746,12 @@ class Communicator { } } - Future vote(String userName, String permlink) async { + Future vote( + String accessToken, String userName, String permlink) async { var headers = { 'Accept': 'application/json, text/plain, */*', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + "authorization": "Bearer $accessToken" }; try { var body = json.encode({ @@ -765,6 +767,7 @@ class Communicator { return ActionResponse( data: json.decode(response.body)['id'], valid: true, error: ''); } else { + log(json.decode(response.body).toString()); return ActionResponse(data: '', valid: false, error: 'Server Error'); } } catch (e) { diff --git a/lib/src/widgets/story_player.dart b/lib/src/widgets/story_player.dart index 6ad8e68d..e9bd5180 100644 --- a/lib/src/widgets/story_player.dart +++ b/lib/src/widgets/story_player.dart @@ -255,6 +255,7 @@ class _StoryPlayerState extends State { hasKey: widget.data.keychainData?.hasId ?? "", hasAuthKey: widget.data.keychainData?.hasAuthKey ?? "", accessToken: widget.data.accessToken, + postingAuthority: widget.data.postingAuthority, activeVotes: postInfo!.activeVotes, onClose: () {}, onDone: () { diff --git a/lib/src/widgets/upvote_button.dart b/lib/src/widgets/upvote_button.dart index 3f2b8ff2..e95c1773 100644 --- a/lib/src/widgets/upvote_button.dart +++ b/lib/src/widgets/upvote_button.dart @@ -88,6 +88,7 @@ class _UpvoteButtonState extends State { hasKey: widget.appData.keychainData?.hasId ?? "", hasAuthKey: widget.appData.keychainData?.hasAuthKey ?? "", accessToken: widget.appData.accessToken, + postingAuthority: widget.appData.postingAuthority, activeVotes: [], onClose: () {}, onDone: () { From f93ed636e53fd4ce70c6ee9c17322ed793b5c0af Mon Sep 17 00:00:00 2001 From: sagar Date: Thu, 15 Feb 2024 18:23:25 +0530 Subject: [PATCH 375/466] bug fix - play offline podcast, tick icon if ofline, offline delete --- .../controller/podcast_controller.dart | 40 +++++++++++++------ .../audio_player_core_controls.dart | 14 ++++--- .../new_pod_cast_epidose_player.dart | 11 +++-- 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/lib/src/screens/podcast/controller/podcast_controller.dart b/lib/src/screens/podcast/controller/podcast_controller.dart index 34d759e4..a8b8d807 100644 --- a/lib/src/screens/podcast/controller/podcast_controller.dart +++ b/lib/src/screens/podcast/controller/podcast_controller.dart @@ -32,9 +32,7 @@ class PodcastController extends ChangeNotifier { bool isOffline(String name, String episodeId) { if (externalDir != null) { for (var item in externalDir.listSync()) { - if (decodeAudioName( - item.path, - ) == + if (decodeAudioName(item.path, episodeId: episodeId) == decodeAudioName(name, episodeId: episodeId)) { // print('offline'); return true; @@ -47,24 +45,36 @@ class PodcastController extends ChangeNotifier { String getOfflineUrl(String url, String episodeId) { for (var item in externalDir.listSync()) { - if (decodeAudioName(item.path) == decodeAudioName(url, episodeId: episodeId)) { + if (decodeAudioName(item.path) == + decodeAudioName(url, episodeId: episodeId)) { return item.path.toString(); } } return ""; } - String decodeAudioName(String name, {String? episodeId,bool isAudio = true}) { + String decodeAudioName(String name, + {String? episodeId, bool isAudio = true}) { String decodedName = name.split('/').last; String target = isAudio ? ".mp3" : ".mp4"; int index = decodedName.indexOf(target); + String? id; + if (episodeId != null) { + id = removeUnwantedCharacters(episodeId); + } if (index != -1) { decodedName = decodedName.substring(0, index + target.length); } - if (episodeId == null) { + if (id == null) { return decodedName; } - return "$episodeId$decodedName"; + return "$id$decodedName"; + } + + String removeUnwantedCharacters(String input) { + RegExp regex = RegExp( + r'[^a-zA-Z0-9\s]'); // Matches anything that is not a letter, digit, or whitespace + return input.replaceAll(regex, ''); } //retrieve liked podcast from local @@ -130,7 +140,8 @@ class PodcastController extends ChangeNotifier { } //sotre the single podcast episode locally if user likes it - void storeLikedPodcastEpisodeLocally(PodcastEpisode item, {bool forceRemove = false}) { + void storeLikedPodcastEpisodeLocally(PodcastEpisode item, + {bool forceRemove = false}) { final String key = _likedPodcastEpisodeLocalKey; if (box.read(key) != null) { List json = box.read(key); @@ -160,12 +171,15 @@ class PodcastController extends ChangeNotifier { } //retrieve the single podcast episodes for liked or offline - List likedOrOfflinepodcastEpisodes({required bool isOffline}) { + List likedOrOfflinepodcastEpisodes( + {required bool isOffline}) { final box = GetStorage(); - final String key = isOffline ? _offlinePodcastLocalKey : _likedPodcastEpisodeLocalKey; + final String key = + isOffline ? _offlinePodcastLocalKey : _likedPodcastEpisodeLocalKey; if (box.read(key) != null) { List json = box.read(key); - List items = json.map((e) => PodcastEpisode.fromJson(e)).toList(); + List items = + json.map((e) => PodcastEpisode.fromJson(e)).toList(); return items; } else { return []; @@ -178,8 +192,10 @@ class PodcastController extends ChangeNotifier { var item = externalDir.listSync()[i]; if (decodeAudioName( item.path, + episodeId: episode.id ) == - decodeAudioName(episode.enclosureUrl ?? "", episodeId: episode.id)) { + decodeAudioName(episode.enclosureUrl ?? "", + episodeId: episode.id)) { externalDir.listSync()[i].delete(); final String key = _offlinePodcastLocalKey; if (box.read(key) != null) { diff --git a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart index b13edcb8..0d90bce2 100644 --- a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart +++ b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart @@ -1,7 +1,7 @@ import 'dart:async'; +import 'dart:io'; import 'package:audio_service/audio_service.dart'; import 'package:audio_session/audio_session.dart'; -import 'package:dart_rss/domain/media/media.dart'; import 'package:just_audio/just_audio.dart'; import 'package:rxdart/rxdart.dart'; import 'package:video_player/video_player.dart'; @@ -52,7 +52,9 @@ abstract class AudioPlayerHandler implements AudioHandler { VideoPlayerController? videoPlayerController; - void setUpVideoController(String url,); + void setUpVideoController( + String url, + ); void disposeVideoController(); @@ -89,7 +91,9 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler return isVideo && videoPlayerController != null; } - void setUpVideoController(String url,) { + void setUpVideoController( + String url, + ) { disposeVideoController(); if (url.startsWith("http")) { this.videoPlayerController = VideoPlayerController.networkUrl( @@ -97,7 +101,7 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler videoPlayerOptions: VideoPlayerOptions(allowBackgroundPlayback: true)) ..initialize(); } else { - this.videoPlayerController = VideoPlayerController.asset(url, + this.videoPlayerController = VideoPlayerController.file(File(url), videoPlayerOptions: VideoPlayerOptions(allowBackgroundPlayback: true)) ..initialize(); } @@ -237,7 +241,7 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler _mediaItemExpando[audioSource] = mediaItem; return audioSource; } else { - final audioSource = AudioSource.asset(mediaItem.id); + final audioSource = AudioSource.file(mediaItem.id); _mediaItemExpando[audioSource] = mediaItem; return audioSource; } diff --git a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart index 5810e312..a9c994cb 100644 --- a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart +++ b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart @@ -61,6 +61,7 @@ class _NewPodcastEpidosePlayerState extends State { void initState() { super.initState(); currentPodcastEpisode = widget.podcastEpisodes[currentPodcastIndex]; + log(currentPodcastEpisode.enclosureUrl!); _setUpVideo(); podcastController = context.read(); originalImage = currentPodcastEpisode.image; @@ -79,12 +80,10 @@ class _NewPodcastEpidosePlayerState extends State { } void _setUpVideo() { - _audioHandler.disposeVideoController(); - log(currentPodcastEpisode.enclosureUrl!); if (!currentPodcastEpisode.isAudio) { _audioHandler.isVideo = true; _audioHandler.setUpVideoController(currentPodcastEpisode.enclosureUrl!); - log('video'); + } else { _audioHandler.isVideo = false; } } @@ -131,9 +130,9 @@ class _NewPodcastEpidosePlayerState extends State { children: [ _audioHandler.shouldPlayVideo() ? SizedBox( - height: MediaQuery.of(context).size.height * 0.45, - width: double.infinity, - child: VideoPlayer(_audioHandler.videoPlayerController!)) + height: MediaQuery.of(context).size.height * 0.45, + child: VideoPlayer(_audioHandler.videoPlayerController!), + ) : Container( constraints: BoxConstraints( maxHeight: From 80a586b8a1455a154117a847d353ceea06cc4ec5 Mon Sep 17 00:00:00 2001 From: sagar Date: Thu, 15 Feb 2024 18:55:42 +0530 Subject: [PATCH 376/466] offline video play --- lib/src/models/podcast/podcast_episodes.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/models/podcast/podcast_episodes.dart b/lib/src/models/podcast/podcast_episodes.dart index 80e99017..39ee4283 100644 --- a/lib/src/models/podcast/podcast_episodes.dart +++ b/lib/src/models/podcast/podcast_episodes.dart @@ -90,7 +90,7 @@ class PodcastEpisode { factory PodcastEpisode.fromJson(Map json) => PodcastEpisode( id: json["id"].toString(), - isAudio: json['enclosureType']?.contains('audio') ?? true, + isAudio:json['isAudio'] ?? json['enclosureType']?.contains('audio') ?? true, title: json["title"], link: json["link"], description: json["description"], @@ -129,6 +129,7 @@ class PodcastEpisode { "duration": duration, "episode": episode, "image": image, - 'chaptersUrl': chaptersUrl + 'chaptersUrl': chaptersUrl, + 'isAudio': isAudio }; } From 3ebd4642f47d2a74a36f93673b2b3a63d896c714 Mon Sep 17 00:00:00 2001 From: sagar Date: Fri, 16 Feb 2024 14:56:54 +0530 Subject: [PATCH 377/466] stop dowload and video aspect ration --- .../audio_player_core_controls.dart | 5 ++ .../new_pod_cast_epidose_player.dart | 16 +++++- .../download_podcast_button.dart | 55 +++++++++++++------ 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart index 0d90bce2..1765d6c6 100644 --- a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart +++ b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'package:audio_service/audio_service.dart'; import 'package:audio_session/audio_session.dart'; +import 'package:flutter/foundation.dart'; import 'package:just_audio/just_audio.dart'; import 'package:rxdart/rxdart.dart'; import 'package:video_player/video_player.dart'; @@ -51,6 +52,7 @@ abstract class AudioPlayerHandler implements AudioHandler { ValueStream get speed; VideoPlayerController? videoPlayerController; + ValueNotifier aspectRatioNotifier = ValueNotifier(null); void setUpVideoController( String url, @@ -85,6 +87,7 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler bool isVideo = false; VideoPlayerController? videoPlayerController; + ValueNotifier aspectRatioNotifier = ValueNotifier(null); @override bool shouldPlayVideo() { @@ -106,12 +109,14 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler ..initialize(); } videoPlayerController!.addListener(() { + aspectRatioNotifier.value = videoPlayerController!.value.aspectRatio; _broadcastState(_player.playbackEvent); }); } void disposeVideoController() { if (videoPlayerController != null) { + aspectRatioNotifier.value = null; videoPlayerController!.seekTo(Duration.zero); videoPlayerController!.removeListener(() { _broadcastState(_player.playbackEvent); diff --git a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart index a9c994cb..6aafb5e5 100644 --- a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart +++ b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart @@ -130,9 +130,19 @@ class _NewPodcastEpidosePlayerState extends State { children: [ _audioHandler.shouldPlayVideo() ? SizedBox( - height: MediaQuery.of(context).size.height * 0.45, - child: VideoPlayer(_audioHandler.videoPlayerController!), - ) + height: MediaQuery.of(context).size.height * 0.45, + child: Center( + child: ValueListenableBuilder( + valueListenable: _audioHandler.aspectRatioNotifier, + builder: (context, aspectRatio, child) { + return AspectRatio( + aspectRatio: aspectRatio ?? 1.5, + child: child); + }, + child: VideoPlayer( + _audioHandler.videoPlayerController!), + )), + ) : Container( constraints: BoxConstraints( maxHeight: diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart index 592dd83f..061fb8ae 100644 --- a/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart @@ -27,7 +27,7 @@ class _DownloadPodcastButtonState extends State { late PodcastController podcastController; final ValueNotifier downloadProgress = ValueNotifier(0); DownloadStatus status = DownloadStatus.download; - + String? taskId; ReceivePort _port = ReceivePort(); @override @@ -95,19 +95,30 @@ class _DownloadPodcastButtonState extends State { final theme = Theme.of(context); final iconColor = widget.color; if (status == DownloadStatus.downloading) { - return SizedBox( - height: 20, - width: 20, - child: ValueListenableBuilder( - valueListenable: downloadProgress, - builder: (context, progress, child) { - return CircularProgressIndicator( - strokeWidth: 2, - value: progress / 100, - valueColor: AlwaysStoppedAnimation(iconColor), - backgroundColor: theme.primaryColorLight.withOpacity(0.4), - ); - }), + return Stack( + alignment: Alignment.center, + children: [ + SizedBox( + height: 25, + width: 25, + child: ValueListenableBuilder( + valueListenable: downloadProgress, + builder: (context, progress, child) { + return CircularProgressIndicator( + strokeWidth: 2, + value: progress / 100, + valueColor: AlwaysStoppedAnimation(iconColor), + backgroundColor: theme.primaryColorLight.withOpacity(0.4), + ); + }), + ), + IconButton( + onPressed: _cancelDownload, + icon: Icon( + Icons.stop, + size: 17.5, + )) + ], ); } else if (podcastController.isOffline( widget.episode.enclosureUrl ?? "", widget.episode.id.toString()) || @@ -134,15 +145,27 @@ class _DownloadPodcastButtonState extends State { } } + void _cancelDownload() { + if (taskId != null) { + FlutterDownloader.cancel(taskId: taskId!); + FlutterDownloader.remove(taskId: taskId!, shouldDeleteContent: true); + setState(() { + taskId = null; + status = DownloadStatus.download; + }); + } + } + void download(String url, String savePath) async { setState(() { status = DownloadStatus.downloading; }); - FlutterDownloader.enqueue( + taskId = await FlutterDownloader.enqueue( url: url, savedDir: savePath, fileName: podcastController.decodeAudioName(widget.episode.enclosureUrl!, - episodeId: widget.episode.id.toString(),isAudio: widget.episode.isAudio), + episodeId: widget.episode.id.toString(), + isAudio: widget.episode.isAudio), showNotification: true, openFileFromNotification: true, ); From 79168ce214d71cf0999bd4f504722b73022d8f81 Mon Sep 17 00:00:00 2001 From: sagar Date: Fri, 16 Feb 2024 18:00:15 +0530 Subject: [PATCH 378/466] removed acela cores --- lib/main.dart | 3 + .../models/user_stream/hive_user_stream.dart | 3 +- .../home_screen/video_upload_sheet.dart | 1 + lib/src/screens/login/ha_login_screen.dart | 296 +++++------------- .../account_settings_screen.dart | 6 +- .../screens/my_account/my_account_screen.dart | 7 +- .../update_thumb/update_thumb_screen.dart | 2 - .../update_video/video_details_info.dart | 9 +- lib/src/screens/settings/settings_screen.dart | 9 +- .../upload/new_video_upload_screen.dart | 2 - .../upload/podcast/audio_details_info.dart | 5 +- .../upload/video/mixins/video_save_mixin.dart | 20 +- .../video/mixins/video_upload_mixin.dart | 25 +- .../upload/video/video_upload_screen.dart | 3 +- .../hive_upvote_dialog.dart | 48 +-- lib/src/utils/communicator.dart | 15 +- 16 files changed, 157 insertions(+), 297 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 6c705cdf..e6845848 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -126,6 +126,7 @@ class _MyAppState extends State { accessToken: null, postingKey: null, username: null, + cookie: null, postingAuthority: null, rpc: 'api.hive.blog', union: GQLCommunicator.defaultGQLServer, @@ -154,6 +155,7 @@ class _MyAppState extends State { const storage = FlutterSecureStorage(); String? username = await storage.read(key: 'username'); String? postingKey = await storage.read(key: 'postingKey'); + String? cookie = await storage.read(key: 'cookie'); String? accessToken = await storage.read(key: 'accessToken'); String? hasId = await storage.read(key: 'hasId'); String? hasExpiry = await storage.read(key: 'hasExpiry'); @@ -185,6 +187,7 @@ class _MyAppState extends State { hasId: hasId, ) : null, + cookie: cookie, accessToken: accessToken, postingAuthority: postingAuth, resolution: resolution, diff --git a/lib/src/models/user_stream/hive_user_stream.dart b/lib/src/models/user_stream/hive_user_stream.dart index 5fbf02e3..ddcf53e5 100644 --- a/lib/src/models/user_stream/hive_user_stream.dart +++ b/lib/src/models/user_stream/hive_user_stream.dart @@ -22,7 +22,7 @@ class HiveSocketData { class HiveUserData { String? username; String? postingKey; - // String? cookie; + String? cookie; String? language; HiveKeychainData? keychainData; String resolution; @@ -37,6 +37,7 @@ class HiveUserData { required this.postingKey, required this.keychainData, required this.accessToken, + required this.cookie, required this.resolution, required this.rpc, required this.union, diff --git a/lib/src/screens/home_screen/video_upload_sheet.dart b/lib/src/screens/home_screen/video_upload_sheet.dart index 7233dbc0..e1e88796 100644 --- a/lib/src/screens/home_screen/video_upload_sheet.dart +++ b/lib/src/screens/home_screen/video_upload_sheet.dart @@ -100,6 +100,7 @@ class VideoUploadSheet { username: null, postingKey: null, keychainData: null, + cookie: null, accessToken: null, postingAuthority: null, resolution: resolution, diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index ff4563ea..a0c16465 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; -import 'package:acela/src/models/action_response.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/new_home_screen.dart'; @@ -30,14 +29,12 @@ class HiveAuthLoginScreen extends StatefulWidget { State createState() => _HiveAuthLoginScreenState(); } -class _HiveAuthLoginScreenState extends State with TickerProviderStateMixin { +class _HiveAuthLoginScreenState extends State + with TickerProviderStateMixin { static const platform = MethodChannel('blog.hive.auth/bridge'); var usernameController = TextEditingController(); late WebSocketChannel socket; String authKey = ''; - String hasIdToken = ''; - String proofOfPayload = ''; - String signedHash = ''; String? qrCode; var loadingQR = false; var timer = 0; @@ -67,7 +64,12 @@ class _HiveAuthLoginScreenState extends State with TickerPr break; case "auth_wait": var uuid = asString(map, 'uuid'); - var jsonData = {"account": usernameController.text, "uuid": uuid, "key": authKey, "host": Communicator.hiveAuthServer}; + var jsonData = { + "account": usernameController.text, + "uuid": uuid, + "key": authKey, + "host": Communicator.hiveAuthServer + }; var jsonString = json.encode(jsonData); var utf8Data = utf8.encode(jsonString); var qr = base64.encode(utf8Data); @@ -106,30 +108,8 @@ class _HiveAuthLoginScreenState extends State with TickerPr qrCode = null; timer = 0; loadingQR = false; - hasIdToken = ''; }); break; - case "challenge_ack": - var messageData = asString(map, 'data'); - decryptChallenge(widget.appData, messageData); - break; - case "challenge_nack": - showError("You denied signing the auth for authentication"); - setState(() { - proofOfPayload = ''; - signedHash = ''; - qrCode = null; - timer = 0; - loadingQR = false; - }); - break; - case "sign_ack": - performSignInWithHAS(true); - break; - case "sign_nack": - showError("3Speak does not have posting authority to your account. You can not publish videos"); - performSignInWithHAS(false); - break; default: log('Default case here'); } @@ -271,15 +251,18 @@ class _HiveAuthLoginScreenState extends State with TickerPr ? Column( children: [ const SizedBox(height: 10), - const Text('Authorize this request with "Keychain for Hive" app.'), + const Text( + 'Authorize this request with "Keychain for Hive" app.'), const SizedBox(height: 20), ElevatedButton( onPressed: () { var url = Uri.parse(qr); launchUrl(url); }, - style: ElevatedButton.styleFrom(backgroundColor: Colors.black), - child: Image.asset('assets/hive-keychain-image.png', width: 220), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black), + child: Image.asset('assets/hive-keychain-image.png', + width: 220), ), const SizedBox(height: 20), SizedBox(height: 10), @@ -318,7 +301,8 @@ class _HiveAuthLoginScreenState extends State with TickerPr onPressed: () { onLoginTapped(appData); }, - style: ElevatedButton.styleFrom(backgroundColor: Colors.black), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black), child: const Text('Login with Posting Key'), ), const SizedBox(height: 10), @@ -331,7 +315,8 @@ class _HiveAuthLoginScreenState extends State with TickerPr Navigator.of(context).push(route); }, child: Text('Sign up'), - style: ElevatedButton.styleFrom(backgroundColor: Colors.black), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black), ), ], ), @@ -355,84 +340,46 @@ class _HiveAuthLoginScreenState extends State with TickerPr }); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); if (bridgeResponse.valid) { - final String doWeHave = await MethodChannel("blog.hive.auth/bridge").invokeMethod( - 'doWeHavePostingAuth', - { - 'username': usernameController.text, - }, + debugPrint("Successful login"); + String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + String union = await storage.read(key: 'union') ?? + GQLCommunicator.defaultGQLServer; + String? lang = await storage.read(key: 'lang'); + await storage.write(key: 'username', value: usernameController.text); + await storage.write(key: 'postingKey', value: postingKey); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); + await storage.delete(key: 'cookie'); + var data = HiveUserData( + accessToken: null, + postingAuthority: null, + username: usernameController.text, + postingKey: postingKey, + keychainData: null, + cookie: null, + resolution: resolution, + rpc: rpc, + union: union, + loaded: true, + language: lang, ); - var doWeHaveResponse = LoginBridgeResponse.fromJsonString(doWeHave); - if (doWeHaveResponse.valid) { - var authority = doWeHaveResponse.data != null && doWeHaveResponse.data == "true"; - if (!authority) { - showError("3Speak does not have posting authority to your account. You can not publish videos"); - } - await storage.write(key: 'postingAuth', value: authority.toString()); - String proofPayload = json.encode({'account': usernameController.text, 'ts': DateTime.now().toIso8601String()}); - const platform = MethodChannel('com.example.acela/auth'); - final String result = await platform.invokeMethod('getProofOfPayload', { - 'username': usernameController.text, - 'postingKey': postingKey, - 'proof': proofPayload, - }); - LoginBridgeResponse actionResponse = LoginBridgeResponse.fromJsonString(result); - if (actionResponse.valid && actionResponse.error == '' && actionResponse.data != null && actionResponse.data!.isNotEmpty) { - var loginApiResponse = await Communicator().login(usernameController.text, proofPayload, actionResponse.data!); - if (loginApiResponse.valid) { - debugPrint("Successful login"); - String resolution = await storage.read(key: 'resolution') ?? '480p'; - String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - String union = await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; - String? lang = await storage.read(key: 'lang'); - await storage.write(key: 'username', value: usernameController.text); - await storage.write(key: 'postingKey', value: postingKey); - await storage.write(key: 'accessToken', value: loginApiResponse.data); - await storage.delete(key: 'hasId'); - await storage.delete(key: 'hasExpiry'); - await storage.delete(key: 'hasAuthKey'); - await storage.delete(key: 'cookie'); - var data = HiveUserData( - username: usernameController.text, - postingKey: postingKey, - keychainData: null, - accessToken: loginApiResponse.data, - postingAuthority: authority.toString(), - resolution: resolution, - rpc: rpc, - union: union, - loaded: true, - language: lang, - ); - server.updateHiveUserData(data); - Navigator.of(context).pop(); - var screen = GQLFeedScreen( - appData: data, - username: usernameController.text, - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).pushReplacement(route); - showMessage('You have successfully logged in as - ${usernameController.text}'); - setState(() { - isLoading = false; - }); - } else { - showError(loginApiResponse.error); - setState(() { - isLoading = false; - }); - } - } else { - showError(actionResponse.error); - setState(() { - isLoading = false; - }); - } - } else { - showError(doWeHaveResponse.error); - setState(() { - isLoading = false; - }); - } + server.updateHiveUserData(data); + var cookie = await Communicator().getValidCookie(data); + log(cookie); + Navigator.of(context).pop(); + var screen = GQLFeedScreen( + appData: data, + username: usernameController.text, + ); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).pushReplacement(route); + showMessage( + 'You have successfully logged in as - ${usernameController.text}'); + setState(() { + isLoading = false; + }); } else { // it is NO valid key showError('Not valid key.'); @@ -445,7 +392,7 @@ class _HiveAuthLoginScreenState extends State with TickerPr isLoading = false; }); log(e.toString()); - if (e == 'No 3Speak Account found with name - ${usernameController.text}') { + if(e == 'No 3Speak Account found with name - ${usernameController.text}'){ await storage.delete(key: 'username'); await storage.delete(key: 'postingKey'); await storage.delete(key: 'hasId'); @@ -456,6 +403,7 @@ class _HiveAuthLoginScreenState extends State with TickerPr username: null, postingKey: null, keychainData: null, + cookie: null, accessToken: null, postingAuthority: null, resolution: '480p', @@ -476,94 +424,21 @@ class _HiveAuthLoginScreenState extends State with TickerPr socket.sink.close(); } - void decryptChallenge(HiveUserData data, String encryptedData) async { - final String response = await platform.invokeMethod('getDecryptedChallenge', { - 'username': usernameController.text, - 'authKey': authKey, - 'data': encryptedData, - }); - var bridgeResponse = LoginBridgeResponse.fromJsonString(response); - if (bridgeResponse.valid && bridgeResponse.data != null && bridgeResponse.data!.isNotEmpty) { - setState(() { - signedHash = bridgeResponse.data!; - }); - final String postingAuthResponse = await platform.invokeMethod('getPostingAuthOps', { - 'username': usernameController.text, - 'authKey': authKey, - }); - var postingAuthBridgeResponse = LoginBridgeResponse.fromJsonString(postingAuthResponse); - if (postingAuthBridgeResponse.valid) { - if (postingAuthBridgeResponse.data != null && postingAuthBridgeResponse.data!.isNotEmpty) { - // get posting authority here. - var socketData = { - "cmd": "sign_req", - "account": usernameController.text, - "token": hasIdToken, - "data": bridgeResponse.data!, - }; - var jsonEncodedData = json.encode(socketData); - socket.sink.add(jsonEncodedData); - } else { - performSignInWithHAS(true); - } - } else { - showMessage('Error getting posting authority details. Please try again.'); - } - } else { - showMessage('Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); - } - } - - void performSignInWithHAS(bool authority) async { - debugPrint("Signed proof is $signedHash"); - debugPrint("Proof of Payload is $proofOfPayload"); - debugPrint("Username is ${usernameController.text}"); - var loginApiResponse = await Communicator().login(usernameController.text, proofOfPayload, signedHash); - String resolution = await storage.read(key: 'resolution') ?? '480p'; - String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - String union = await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; - String? lang = await storage.read(key: 'lang'); - await storage.write(key: 'username', value: usernameController.text); - await storage.delete(key: 'postingKey'); - await storage.write(key: 'accessToken', value: loginApiResponse.data); - await storage.write(key: 'postingAuth', value:authority.toString()); - var data = HiveUserData( - username: usernameController.text, - postingKey: null, - keychainData: null, - accessToken: loginApiResponse.data, - postingAuthority: authority.toString(), - resolution: resolution, - rpc: rpc, - union: union, - loaded: true, - language: lang, - ); - server.updateHiveUserData(data); - Navigator.of(context).pop(); - var screen = GQLFeedScreen( - appData: data, - username: usernameController.text, - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).pushReplacement(route); - showMessage('You have successfully logged in as - ${usernameController.text}'); - setState(() { - isLoading = false; - }); - } - void decryptData(HiveUserData data, String encryptedData) async { - final String response = await platform.invokeMethod('getDecryptedHASToken', { + final String response = + await platform.invokeMethod('getDecryptedHASToken', { 'username': usernameController.text, 'authKey': authKey, 'data': encryptedData, }); var bridgeResponse = LoginBridgeResponse.fromJsonString(response); - if (bridgeResponse.valid && bridgeResponse.data != null && bridgeResponse.data!.isNotEmpty) { + if (bridgeResponse.valid && + bridgeResponse.data != null && + bridgeResponse.data!.isNotEmpty) { var tokenData = bridgeResponse.data!.split(","); if (tokenData.isEmpty || tokenData.length != 2) { - showMessage('Did not find token & expiry details from HiveAuth. Please go back & try again.'); + showMessage( + 'Did not find token & expiry details from HiveAuth. Please go back & try again.'); } else { const storage = FlutterSecureStorage(); await storage.write(key: 'username', value: usernameController.text); @@ -580,6 +455,7 @@ class _HiveAuthLoginScreenState extends State with TickerPr hasExpiry: tokenData[1], hasId: tokenData[0], ), + cookie: null, accessToken: null, postingAuthority: null, resolution: data.resolution, @@ -589,35 +465,19 @@ class _HiveAuthLoginScreenState extends State with TickerPr language: data.language, ); server.updateHiveUserData(newData); - showMessage('You have successfully logged in with Hive Auth with user - ${usernameController.text}'); - final String eChallengeResponse = await platform.invokeMethod('getEncryptedChallenge', { - 'username': usernameController.text, - 'authKey': authKey, - }); - var eChallengeResponseData = json.decode(eChallengeResponse)['data'] as String; - var eData = eChallengeResponseData.split("|")[0]; - setState(() { - hasIdToken = tokenData[0]; - proofOfPayload = eChallengeResponseData.split("|")[1]; - }); - var socketData = { - "cmd": "challenge_req", - "account": usernameController.text, - "token": tokenData[0], - "data": eData, - }; - var jsonEncodedData = json.encode(socketData); - socket.sink.add(jsonEncodedData); - // Navigator.of(context).pop(); - // var screen = GQLFeedScreen( - // appData: newData, - // username: usernameController.text, - // ); - // var route = MaterialPageRoute(builder: (c) => screen); - // Navigator.of(context).pushReplacement(route); + showMessage( + 'You have successfully logged in with Hive Auth with user - ${usernameController.text}'); + Navigator.of(context).pop(); + var screen = GQLFeedScreen( + appData: newData, + username: usernameController.text, + ); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).pushReplacement(route); } } else { - showMessage('Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); + showMessage( + 'Something went wrong - ${bridgeResponse.error}. Please go back & try again.'); } } diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index 5655fbd2..0f7ba076 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -3,6 +3,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/new_home_screen.dart'; import 'package:acela/src/screens/my_account/account_settings/widgets/delete_dialog.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -35,6 +36,7 @@ class _AccountSettingsScreenState extends State { username: null, postingKey: null, keychainData: null, + cookie: null, accessToken: null, postingAuthority: null, resolution: resolution, @@ -104,13 +106,10 @@ class _AccountSettingsScreenState extends State { onDelete: () async { Navigator.pop(context); try { - /* - // TO-DO: New Acela Core APIs setState(() { isLoading = true; }); bool status = await Communicator().deleteAccount(data); - log(status.toString()); if (status) { await logout(data); showMessage('Account Deleted Successfully'); @@ -120,7 +119,6 @@ class _AccountSettingsScreenState extends State { setState(() { isLoading = false; }); - */ } catch (e) { setState(() { isLoading = false; diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index f77cb25b..54eb2deb 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -9,6 +9,7 @@ import 'package:acela/src/screens/settings/settings_screen.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; @@ -34,11 +35,9 @@ class _MyAccountScreenState extends State @override void initState() { super.initState(); - /* TO-DO: Acela Core integration setState(() { loadVideos = Communicator().loadVideos(widget.data); }); - */ _tabController = TabController(length: 3, vsync: this); _tabController.addListener(() { setState(() { @@ -91,11 +90,9 @@ class _MyAccountScreenState extends State actions: [ IconButton( onPressed: () { - /* TO-DO: Acela Core Integration setState(() { loadVideos = Communicator().loadVideos(widget.data); }); - */ }, icon: Icon(Icons.refresh), ), @@ -202,7 +199,6 @@ class _MyAccountScreenState extends State BottomSheetAction( title: Text('Delete Video'), onPressed: (context) async { - /* TO-DO: Acela Core API Integration Navigator.of(context).pop(); showSnackBar('Deleting...', seconds: 60); bool result = @@ -215,7 +211,6 @@ class _MyAccountScreenState extends State } else { showSnackBar("Something went wrong"); } - */ }, ), ); diff --git a/lib/src/screens/my_account/update_thumb/update_thumb_screen.dart b/lib/src/screens/my_account/update_thumb/update_thumb_screen.dart index 31bdfe7c..1eee5761 100644 --- a/lib/src/screens/my_account/update_thumb/update_thumb_screen.dart +++ b/lib/src/screens/my_account/update_thumb/update_thumb_screen.dart @@ -67,7 +67,6 @@ class _UpdateThumbScreenState extends State { } void completeVideo(HiveUserData user) async { - /* TO-DO: New Acela Core APIs setState(() { isCompleting = true; processText = 'Updating video info'; @@ -87,7 +86,6 @@ class _UpdateThumbScreenState extends State { processText = ''; }); } - */ } Widget _thumbnailPicker(HiveUserData user) { diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index 9309bf65..a43f399c 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -3,9 +3,12 @@ import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/global_provider/ipfs_node_provider.dart'; +import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/my_account/video_ops.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; +import 'package:acela/src/screens/my_account/my_account_screen.dart'; import 'package:acela/src/screens/my_account/update_video/add_bene_sheet.dart'; import 'package:acela/src/screens/settings/settings_screen.dart'; import 'package:acela/src/utils/communicator.dart'; @@ -173,7 +176,6 @@ class _VideoDetailsInfoState extends State { 'Please wait. Video is posted on Hive but needs to be marked as published.'); Future.delayed(const Duration(seconds: 6), () async { if (mounted) { - /* TO-DO: Acela Core integration try { await Communicator() .updatePublishState(widget.appData, widget.item.id); @@ -193,7 +195,6 @@ class _VideoDetailsInfoState extends State { 'Video is posted on Hive but needs to be marked as published. Please hit Save button again after few seconds.'); }); } - */ } }); break; @@ -278,7 +279,6 @@ class _VideoDetailsInfoState extends State { var doesPostNotExist = await Communicator() .doesPostNotExist(widget.item.owner, widget.item.permlink, user.rpc); if (doesPostNotExist != true) { - /* TO-DO: Acela-Core integration await Communicator().updatePublishState(user, widget.item.id); setState(() { isCompleting = false; @@ -286,9 +286,7 @@ class _VideoDetailsInfoState extends State { showMessage('Your video was already published.'); showMyDialog(); }); - */ } else { - /* TO-DO: Acela-Core integration var v = await Communicator().updateInfo( user: user, videoId: widget.item.id, @@ -386,7 +384,6 @@ class _VideoDetailsInfoState extends State { } else { throw bridgeResponse.error; } - */ } } catch (e) { showError(e.toString()); diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index abce0065..1726782b 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -5,6 +5,7 @@ import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/new_home_screen.dart'; import 'package:acela/src/screens/my_account/account_settings/widgets/delete_dialog.dart'; import 'package:acela/src/screens/settings/add_cutom_union_indexer.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/foundation.dart'; @@ -90,6 +91,7 @@ class _SettingsScreenState extends State { String? hasId = await storage.read(key: 'hasId'); String? hasExpiry = await storage.read(key: 'hasExpiry'); String? hasAuthKey = await storage.read(key: 'hasAuthKey'); + String? cookie = await storage.read(key: 'cookie'); String? accessToken = await storage.read(key: 'accessToken'); String? postingAuth = await storage.read(key: 'postingAuth') ; String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; @@ -100,6 +102,7 @@ class _SettingsScreenState extends State { HiveUserData( username: username, postingKey: postingKey, + cookie: cookie, accessToken: accessToken, postingAuthority: postingAuth, resolution: optionName, @@ -173,6 +176,7 @@ class _SettingsScreenState extends State { HiveUserData( username: appData.username, postingKey: appData.postingKey, + cookie: appData.cookie, accessToken: appData.accessToken, resolution: appData.resolution, rpc: appData.rpc, @@ -261,6 +265,7 @@ class _SettingsScreenState extends State { username: null, postingKey: null, keychainData: null, + cookie: null, accessToken: null, postingAuthority: null, resolution: resolution, @@ -310,7 +315,6 @@ class _SettingsScreenState extends State { builder: (context) { return DeleteDialog( onDelete: () async { - /* TO-DO: Acela Core integration Navigator.pop(context); try { setState(() { @@ -332,7 +336,6 @@ class _SettingsScreenState extends State { }); showError("Sorry, Something went wrong."); } - */ }, ); }, @@ -449,6 +452,7 @@ class _SettingsScreenState extends State { username: user.username, postingKey: user.postingKey, keychainData: user.keychainData, + cookie: user.cookie, accessToken: user.accessToken, postingAuthority: user.postingAuthority.toString(), resolution: user.resolution, @@ -522,6 +526,7 @@ class _SettingsScreenState extends State { HiveUserData( username: user.username, postingKey: user.postingKey, + cookie: user.cookie, keychainData: user.keychainData, accessToken: user.accessToken, postingAuthority: user.postingAuthority.toString(), diff --git a/lib/src/screens/upload/new_video_upload_screen.dart b/lib/src/screens/upload/new_video_upload_screen.dart index c1374efc..fbf6b418 100644 --- a/lib/src/screens/upload/new_video_upload_screen.dart +++ b/lib/src/screens/upload/new_video_upload_screen.dart @@ -255,7 +255,6 @@ class _NewVideoUploadScreenState extends State { setState(() { didStartMoveToQueue = true; }); - /* TO-DO: new video upload var videoUploadInfo = await Communicator().uploadInfo( user: user!, thumbnail: thumbName, @@ -278,7 +277,6 @@ class _NewVideoUploadScreenState extends State { showMessage('Video is uploaded & moved to encoding queue'); showMyDialog(item); }); - */ // Step 6. Move Video to Queue } else { throw 'User cancelled the video picker'; diff --git a/lib/src/screens/upload/podcast/audio_details_info.dart b/lib/src/screens/upload/podcast/audio_details_info.dart index a45b97d9..93b23abe 100644 --- a/lib/src/screens/upload/podcast/audio_details_info.dart +++ b/lib/src/screens/upload/podcast/audio_details_info.dart @@ -6,6 +6,7 @@ import 'dart:ui' as ui; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/ipfs_node_provider.dart'; +import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/my_account/video_ops.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/my_account/update_video/add_bene_sheet.dart'; @@ -166,7 +167,6 @@ class _AudioDetailsInfoScreenState extends State { }); try { final String ipfsUrl = IpfsNodeProvider().nodeUrl; - /* TO-DO: Acela Core Integration var podcastResponse = await Communicator().uploadPodcast( user: user, size: widget.size, @@ -265,7 +265,6 @@ class _AudioDetailsInfoScreenState extends State { } else { throw bridgeResponse.error; } - */ } catch (e) { showError(e.toString()); setState(() { @@ -361,7 +360,6 @@ class _AudioDetailsInfoScreenState extends State { }); showMessage( 'Please wait. Podcast is posted on Hive but needs to be marked as published.'); - /* TO-DO: Acela Core Integration Future.delayed(const Duration(seconds: 6), () async { if (mounted) { try { @@ -386,7 +384,6 @@ class _AudioDetailsInfoScreenState extends State { } } }); - */ break; case "sign_nack": setState(() { diff --git a/lib/src/screens/upload/video/mixins/video_save_mixin.dart b/lib/src/screens/upload/video/mixins/video_save_mixin.dart index e13b854e..19067438 100644 --- a/lib/src/screens/upload/video/mixins/video_save_mixin.dart +++ b/lib/src/screens/upload/video/mixins/video_save_mixin.dart @@ -2,6 +2,7 @@ import 'package:acela/src/models/my_account/video_ops.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_upload/video_upload_prepare_response.dart'; import 'package:acela/src/screens/settings/settings_screen.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:flutter/cupertino.dart'; class VideoSaveMixin { @@ -25,16 +26,15 @@ class VideoSaveMixin { }) async { try { isSaving.value = true; - // TO-DO: Update here - // await Communicator().updateInfo( - // user: user, - // videoId: item.id, - // title: title, - // description: description, - // isNsfwContent: isNsfwContent, - // tags: tags, - // thumbnail: thumbIpfs.isEmpty ? null : thumbIpfs, - // communityID: communityId); + await Communicator().updateInfo( + user: user, + videoId: item.id, + title: title, + description: description, + isNsfwContent: isNsfwContent, + tags: tags, + thumbnail: thumbIpfs.isEmpty ? null : thumbIpfs, + communityID: communityId); isSaving.value = false; successDialog(); } catch (e) { diff --git a/lib/src/screens/upload/video/mixins/video_upload_mixin.dart b/lib/src/screens/upload/video/mixins/video_upload_mixin.dart index 4010bff2..1c742f54 100644 --- a/lib/src/screens/upload/video/mixins/video_upload_mixin.dart +++ b/lib/src/screens/upload/video/mixins/video_upload_mixin.dart @@ -3,9 +3,13 @@ import 'dart:io'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_upload/upload_response.dart'; import 'package:acela/src/models/video_upload/video_upload_prepare_response.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/enum.dart'; +import 'package:ffmpeg_kit_flutter/ffprobe_kit.dart'; +import 'package:ffmpeg_kit_flutter/media_information_session.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; +import 'package:tus_client/tus_client.dart'; import 'package:video_thumbnail/video_thumbnail.dart'; mixin Upload { @@ -31,19 +35,19 @@ mixin Upload { log('upload started'); int fileSize = _checkFileSize(size); var path = pickedVideoFile.path; - // var videoUploadReponse = await _uploadToServer(path, videoUploadProgress); - // var name = videoUploadReponse.name; + var videoUploadReponse = await _uploadToServer(path, videoUploadProgress); + var name = videoUploadReponse.name; _initiateNextUpload(); var thumbPath = await _getThumbnail(path); _initiateNextUpload(); - // var thumbReponse = await uploadThumbnail(thumbPath); + var thumbReponse = await uploadThumbnail(thumbPath); _initiateNextUpload(); - // log('Uploaded file name is $name'); - // log('Uploaded thumbnail file name is ${thumbReponse.name}'); - // uploadedVideoItem= await _encodeAndUploadInfo(path, - // hiveUserData, thumbReponse.name, originalFileName, fileSize, name); - // uploadStatus.value = UploadStatus.ended; + log('Uploaded file name is $name'); + log('Uploaded thumbnail file name is ${thumbReponse.name}'); + uploadedVideoItem= await _encodeAndUploadInfo(path, + hiveUserData, thumbReponse.name, originalFileName, fileSize, name); + uploadStatus.value = UploadStatus.ended; _initiateNextUpload(); } @@ -95,11 +99,9 @@ mixin Upload { } return fileSize; } -/* TO-DO: This with acela Core Future uploadThumbnail(String path) async { thumbnailUploadStatus.value = UploadStatus.started; - var thumbReponse = await _uploadToServer(path, thumbnailUploadProgress); - thumbnailUploadStatus.value = UploadStatus.ended; + var thumbReponse = await _uploadToServer(path, thumbnailUploadProgress);thumbnailUploadStatus.value = UploadStatus.ended; thumbnailUploadResponse.value = (thumbReponse); return thumbReponse; } @@ -153,5 +155,4 @@ mixin Upload { ); return UploadResponse(name: name, url: url); } - */ } diff --git a/lib/src/screens/upload/video/video_upload_screen.dart b/lib/src/screens/upload/video/video_upload_screen.dart index 7de9d791..89691264 100644 --- a/lib/src/screens/upload/video/video_upload_screen.dart +++ b/lib/src/screens/upload/video/video_upload_screen.dart @@ -155,8 +155,7 @@ class _VideoUploadScreenState extends State { thumbnailUploadProgress: controller.thumbnailUploadProgress, thumbnailUploadRespone: controller.thumbnailUploadResponse, onUploadFile: (file) { - // TO-DO: upload thumbnail - // controller.uploadThumbnail(file.path); + controller.uploadThumbnail(file.path); }, ); } diff --git a/lib/src/screens/video_details_screen/hive_upvote_dialog.dart b/lib/src/screens/video_details_screen/hive_upvote_dialog.dart index e2f12440..86718065 100644 --- a/lib/src/screens/video_details_screen/hive_upvote_dialog.dart +++ b/lib/src/screens/video_details_screen/hive_upvote_dialog.dart @@ -244,29 +244,29 @@ class _HiveUpvoteDialogState extends State { var voteValue = sliderValue * 10000; var user = data.username; if (user == null) return; - if (widget.accessToken != null && widget.postingAuthority) { - ActionResponse response = await Communicator() - .vote(widget.accessToken!, widget.author, widget.permlink); - if (response.valid && response.error.isEmpty) { - // Future.delayed(const Duration(seconds: 6), () { - if (mounted) { - setState(() { - isUpVoting = false; - widget.onDone(); - Navigator.of(context).pop(); - }); - } - // }); - } else { - showError(response.error); - if (isUpVoting && mounted) { - setState(() { - isUpVoting = false; - }); - } - } - } - else { + // if (widget.accessToken != null && widget.postingAuthority) { + // ActionResponse response = await Communicator() + // .vote(widget.accessToken!, widget.author, widget.permlink); + // if (response.valid && response.error.isEmpty) { + // // Future.delayed(const Duration(seconds: 6), () { + // if (mounted) { + // setState(() { + // isUpVoting = false; + // widget.onDone(); + // Navigator.of(context).pop(); + // }); + // } + // // }); + // } else { + // showError(response.error); + // if (isUpVoting && mounted) { + // setState(() { + // isUpVoting = false; + // }); + // } + // } + // } + // else { try { const platform = MethodChannel('com.example.acela/auth'); final String result = await platform.invokeMethod('voteContent', { @@ -320,7 +320,7 @@ class _HiveUpvoteDialogState extends State { } showError('Something went wrong.\n${e.toString()}'); } - } + // } } Widget _showQRCodeAndKeychainButton(String qr) { diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index d225d907..e33ec1ed 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:developer'; +import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/action_response.dart'; import 'package:acela/src/models/communities_models/request/communities_request_model.dart'; import 'package:acela/src/models/communities_models/response/communities_response_models.dart'; @@ -9,11 +10,17 @@ import 'package:acela/src/models/hive_post_info/hive_user_posting_key.dart'; import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/login/memo_response.dart'; import 'package:acela/src/models/my_account/video_ops.dart'; +import 'package:acela/src/models/podcast/upload/podcast_episode_upload_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_upload/does_post_exists.dart'; +import 'package:acela/src/models/video_upload/video_upload_complete_request.dart'; +import 'package:acela/src/models/video_upload/video_upload_login_response.dart'; +import 'package:acela/src/models/video_upload/video_upload_prepare_response.dart'; +import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:http/http.dart' as http; import 'package:http/http.dart'; @@ -213,7 +220,6 @@ class Communicator { return memo.decrypted.replaceFirst("#", ''); } -/* OLD APIs Future getValidCookie(HiveUserData user) async { var uri = '${Communicator.tsServer}/mobile/login?username=${user.username}'; if (user.keychainData != null && user.postingKey == null) { @@ -260,6 +266,8 @@ class Communicator { keychainData: user.keychainData, union: union, cookie: cookie, + postingAuthority: null, + accessToken: null, resolution: resolution, rpc: rpc, loaded: true, @@ -293,6 +301,8 @@ class Communicator { String union = await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; var newData = HiveUserData( + postingAuthority: null, + accessToken: null, username: user.username, postingKey: user.postingKey, keychainData: user.keychainData, @@ -444,7 +454,6 @@ class Communicator { } } - */ Future> loadAnyFeed(Uri uri) async { var request = http.Request('GET', uri); http.StreamedResponse response = await request.send(); @@ -521,7 +530,6 @@ class Communicator { } } -/* OLD APIS. Use Acela-core now. Future> loadVideos(HiveUserData user) async { log("Starting fetch videos ${DateTime.now().toIso8601String()}"); var cookie = await getValidCookie(user); @@ -705,7 +713,6 @@ class Communicator { rethrow; } } -*/ Future login( String userName, String proofOfPayload, From e4d59c70aa0daf85c5eec1a1b1d42c1c6a5756aa Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 16 Feb 2024 22:41:25 +0530 Subject: [PATCH 379/466] release related work in progress --- android/app/src/main/assets/index.html | 75 ++++++++++++++++---------- ios/Runner/public/index.html | 75 ++++++++++++++++---------- lib/src/utils/communicator.dart | 8 +-- 3 files changed, 98 insertions(+), 60 deletions(-) diff --git a/android/app/src/main/assets/index.html b/android/app/src/main/assets/index.html index c196a60c..b4aff110 100644 --- a/android/app/src/main/assets/index.html +++ b/android/app/src/main/assets/index.html @@ -20,7 +20,27 @@ > + + + + - + \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index e6845848..111bcf7f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,10 +3,10 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/image_resolution_provider.dart'; import 'package:acela/src/global_provider/video_setting_provider.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/screens/home_screen/new_home_screen.dart'; import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; import 'package:acela/src/screens/upload/video/controller/video_upload_controller.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; +import 'package:acela/src/utils/routes/app_router.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_crashlytics/firebase_crashlytics.dart'; @@ -206,19 +206,9 @@ class AcelaApp extends StatelessWidget { @override Widget build(BuildContext context) { var isDarkMode = Provider.of(context); - var userData = Provider.of(context); - return MaterialApp( + return MaterialApp.router( title: 'Acela - 3Speak App', - home: userData.loaded - ? userData.username != null - ? GQLFeedScreen(appData: userData, username: userData.username!) - : GQLFeedScreen(appData: userData, username: null) - : Scaffold( - appBar: AppBar(title: const Text('3Speak')), - body: const Center( - child: CircularProgressIndicator(), - ), - ), + routerConfig: AppRouter.router, theme: isDarkMode ? ThemeData.dark().copyWith( primaryColor: Colors.deepPurple, diff --git a/lib/src/models/navigation_models/new_video_detail_screen_navigation_model.dart b/lib/src/models/navigation_models/new_video_detail_screen_navigation_model.dart new file mode 100644 index 00000000..602845d9 --- /dev/null +++ b/lib/src/models/navigation_models/new_video_detail_screen_navigation_model.dart @@ -0,0 +1,12 @@ +import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; +import 'package:better_player/better_player.dart'; +import 'package:flutter/material.dart'; + +class NewVideoDetailScreenNavigationParameter { + final BetterPlayerController? betterPlayerController; + final GQLFeedItem? item; + final VoidCallback? onPop; + + NewVideoDetailScreenNavigationParameter( + {this.betterPlayerController, this.item,this.onPop}); +} diff --git a/lib/src/models/podcast/podcast_episodes.dart b/lib/src/models/podcast/podcast_episodes.dart index 39ee4283..a333d079 100644 --- a/lib/src/models/podcast/podcast_episodes.dart +++ b/lib/src/models/podcast/podcast_episodes.dart @@ -90,7 +90,8 @@ class PodcastEpisode { factory PodcastEpisode.fromJson(Map json) => PodcastEpisode( id: json["id"].toString(), - isAudio:json['isAudio'] ?? json['enclosureType']?.contains('audio') ?? true, + isAudio: + json['isAudio'] ?? json['enclosureType']?.contains('audio') ?? true, title: json["title"], link: json["link"], description: json["description"], @@ -132,4 +133,36 @@ class PodcastEpisode { 'chaptersUrl': chaptersUrl, 'isAudio': isAudio }; + + PodcastEpisode copyWith({ + String? id, + String? title, + String? link, + String? description, + int? datePublished, + String? datePublishedPretty, + String? enclosureUrl, + int? duration, + int? episode, + String? image, + String? guid, + String? chaptersUrl, + bool? isAudio, + }) { + return PodcastEpisode( + id: id ?? this.id, + title: title ?? this.title, + link: link ?? this.link, + description: description ?? this.description, + datePublished: datePublished ?? this.datePublished, + datePublishedPretty: datePublishedPretty ?? this.datePublishedPretty, + enclosureUrl: enclosureUrl ?? this.enclosureUrl, + duration: duration ?? this.duration, + episode: episode ?? this.episode, + image: image ?? this.image, + guid: guid ?? this.guid, + chaptersUrl: chaptersUrl ?? this.chaptersUrl, + isAudio: isAudio ?? this.isAudio, + ); + } } diff --git a/lib/src/screens/communities_screen/community_details/community_details_screen.dart b/lib/src/screens/communities_screen/community_details/community_details_screen.dart index c41ebb7a..43552d09 100644 --- a/lib/src/screens/communities_screen/community_details/community_details_screen.dart +++ b/lib/src/screens/communities_screen/community_details/community_details_screen.dart @@ -7,15 +7,16 @@ import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_list.dart'; import 'package:acela/src/screens/stories/story_feed_list.dart'; -import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/utils/routes/routes.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/retry.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:go_router/go_router.dart'; import 'package:http/http.dart'; import 'package:http/http.dart' as http; import 'package:provider/provider.dart'; @@ -96,8 +97,7 @@ class _CommunityDetailScreenState extends State } void onUserTap(HomeFeedItem item) { - Navigator.of(context).push(MaterialPageRoute( - builder: (c) => UserChannelScreen(owner: item.author))); + context.pushNamed(Routes.userView, pathParameters: {'author': item.author}); } Widget _screen(HiveUserData appData) { diff --git a/lib/src/screens/favourites/user_favourites.dart b/lib/src/screens/favourites/user_favourites.dart index 08166183..9c67e8db 100644 --- a/lib/src/screens/favourites/user_favourites.dart +++ b/lib/src/screens/favourites/user_favourites.dart @@ -44,7 +44,7 @@ class _UserFavouritesState extends State return Scaffold( appBar: AppBar( title: ListTile( - title: Text('Favourites'), + title: Text('Bookmarks'), subtitle: Text(appBarSubtitle()), ), bottom: TabBar( diff --git a/lib/src/screens/home_screen/default_screen.dart b/lib/src/screens/home_screen/default_screen.dart new file mode 100644 index 00000000..3de6045c --- /dev/null +++ b/lib/src/screens/home_screen/default_screen.dart @@ -0,0 +1,25 @@ +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/home_screen/new_home_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class DefaultView extends StatelessWidget { + const DefaultView({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final userData = Provider.of(context); + return userData.loaded + ? userData.username != null + ? GQLFeedScreen(appData: userData, username: userData.username!) + : GQLFeedScreen(appData: userData, username: null) + : Scaffold( + appBar: AppBar(title: const Text('3Speak')), + body: const Center( + child: CircularProgressIndicator(), + ), + ); + } +} diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart index fc9983c2..af79129d 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart @@ -1,8 +1,8 @@ import 'dart:io'; - import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/image_resolution_provider.dart'; import 'package:acela/src/global_provider/video_setting_provider.dart'; +import 'package:acela/src/models/navigation_models/new_video_detail_screen_navigation_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/controller/home_feed_video_controller.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_full_screen_button.dart'; @@ -10,12 +10,11 @@ import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/home import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/home_feed_video_timer.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/mute_unmute_button.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/play_pause_button.dart'; -import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; -import 'package:acela/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/new_video_details/video_detail_favourite_provider.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; +import 'package:acela/src/utils/routes/routes.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/cached_image.dart'; import 'package:acela/src/widgets/upvote_button.dart'; @@ -23,6 +22,7 @@ import 'package:better_player/better_player.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:timeago/timeago.dart' as timeago; @@ -243,14 +243,15 @@ class _NewFeedListItemState extends State ) : _videoStack(thumbnail), SizedBox( - height:widget.isGridView ? 75 : null, + height: widget.isGridView ? 75 : null, child: Padding( padding: const EdgeInsets.only( top: 10.0, bottom: 5, left: 13, right: 13), child: Row( - crossAxisAlignment:!widget.isGridView && isTitleOneLine(titleStyle) - ? CrossAxisAlignment.center - : CrossAxisAlignment.start, + crossAxisAlignment: + !widget.isGridView && isTitleOneLine(titleStyle) + ? CrossAxisAlignment.center + : CrossAxisAlignment.start, children: [ InkWell( child: ClipOval( @@ -397,7 +398,9 @@ class _NewFeedListItemState extends State _interactionTools() ], ) - : widget.isGridView ? Positioned.fill(child: thumbnail) : thumbnail, + : widget.isGridView + ? Positioned.fill(child: thumbnail) + : thumbnail, _timer(), ], ); @@ -425,28 +428,22 @@ class _NewFeedListItemState extends State } void _pushToVideoDetailScreen() async { - var screen = NewVideoDetailsScreen( - betterPlayerController: _betterPlayerController, - item: widget.item!, - appData: widget.appData!); - var route = MaterialPageRoute(builder: (context) => screen); homeFeedVideoController.isUserOnAnotherScreen = true; - await Navigator.of(context).push(route); - homeFeedVideoController.isUserOnAnotherScreen = false; - if (widget.showVideo && - _betterPlayerController == null && - !homeFeedVideoController.isUserOnAnotherScreen) { - setState(() { - _initVideo(); - }); - } + context.pushNamed(Routes.videoDetailsView, + extra: NewVideoDetailScreenNavigationParameter( + betterPlayerController: _betterPlayerController, + item: widget.item, + onPop: onPopFromUserViewOrVideoDetailsView), + pathParameters: {'author': widget.author, 'permlink': widget.permlink}); } void _pushToUserScreen() async { - var screen = UserChannelScreen(owner: widget.author); - var route = MaterialPageRoute(builder: (c) => screen); - homeFeedVideoController.isUserOnAnotherScreen = true; - await Navigator.of(context).push(route); + context.pushNamed(Routes.userView, + pathParameters: {'author': widget.author}, + extra: onPopFromUserViewOrVideoDetailsView); + } + + void onPopFromUserViewOrVideoDetailsView() { homeFeedVideoController.isUserOnAnotherScreen = false; if (widget.showVideo && _betterPlayerController == null && diff --git a/lib/src/screens/home_screen/new_home_screen.dart b/lib/src/screens/home_screen/new_home_screen.dart index 2ef80a09..db2954ad 100644 --- a/lib/src/screens/home_screen/new_home_screen.dart +++ b/lib/src/screens/home_screen/new_home_screen.dart @@ -343,8 +343,8 @@ class _GQLFeedScreenState extends State } fabItems.add( FabOverItemData( - displayName: 'Favourites', - icon: Icons.favorite, + displayName: 'Bookmarks', + icon: Icons.bookmarks, onTap: () { setState(() { isMenuOpen = false; diff --git a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart index f8aaa686..000d0028 100644 --- a/lib/src/screens/leaderboard_screen/leaderboard_screen.dart +++ b/lib/src/screens/leaderboard_screen/leaderboard_screen.dart @@ -1,12 +1,13 @@ import 'dart:core'; - import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/leaderboard_models/leaderboard_model.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; +import 'package:acela/src/utils/routes/routes.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:acela/src/widgets/retry.dart'; import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:http/http.dart' show get; class LeaderboardScreen extends StatefulWidget { @@ -46,8 +47,7 @@ class _LeaderboardScreenState extends State { } void onUserTap(String author) { - Navigator.of(context).push( - MaterialPageRoute(builder: (c) => UserChannelScreen(owner: author))); + context.pushNamed(Routes.userView, pathParameters: {'author': author}); } Widget _medalTile(LeaderboardResponseItem item, String medal, double max) { diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 54eb2deb..1c3405d3 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -10,10 +10,12 @@ import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/utils/routes/routes.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; class MyAccountScreen extends StatefulWidget { const MyAccountScreen({ @@ -64,9 +66,7 @@ class _MyAccountScreenState extends State splashColor: Colors.transparent, contentPadding: EdgeInsets.zero, onTap: () { - var screen = UserChannelScreen(owner: username); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); + context.pushNamed(Routes.userView, pathParameters: {'author': username}); }, leading: CustomCircleAvatar( height: 36, diff --git a/lib/src/screens/podcast/controller/podcast_controller.dart b/lib/src/screens/podcast/controller/podcast_controller.dart index 59d88815..248e7257 100644 --- a/lib/src/screens/podcast/controller/podcast_controller.dart +++ b/lib/src/screens/podcast/controller/podcast_controller.dart @@ -1,8 +1,10 @@ +import 'dart:developer'; import 'dart:io'; import 'package:acela/src/models/podcast/podcast_episodes.dart'; import 'package:acela/src/models/podcast/trending_podcast_response.dart'; import 'package:flutter/material.dart'; import 'package:get_storage/get_storage.dart'; +import 'package:http/http.dart'; import 'package:path_provider/path_provider.dart'; class PodcastController extends ChangeNotifier { @@ -159,14 +161,20 @@ class PodcastController extends ChangeNotifier { } //after downloaing a podcast episode store it locally - void storeOfflinePodcastLocally(PodcastEpisode episode) { + Future storeOfflinePodcastLocally(PodcastEpisode episode) async { + log('saving'); + PodcastEpisode localEpisode = episode; + try { + localEpisode = + episode.copyWith(image: await _saveImage(episode.image!, episode.id!)); + } catch (e) {} final String key = _offlinePodcastLocalKey; if (box.read(key) != null) { List json = box.read(key); - json.add(episode.toJson()); + json.add(localEpisode.toJson()); box.write(key, json); } else { - box.write(key, [episode.toJson()]); + box.write(key, [localEpisode.toJson()]); } } @@ -188,6 +196,8 @@ class PodcastController extends ChangeNotifier { void deleteOfflinePodcastEpisode(PodcastEpisode episode) { if (externalDir != null) { + String decodedId = removeUnwantedCharacters(episode.id!); + _deleteImage(externalDir.path + '/images/$decodedId.jpg'); for (int i = 0; i < externalDir.listSync().length; i++) { var item = externalDir.listSync()[i]; if (decodeAudioName(item.path, episodeId: episode.id) == @@ -204,4 +214,24 @@ class PodcastController extends ChangeNotifier { } } } + + _saveImage(String imageUrl, String identifier) async { + String id = removeUnwantedCharacters(identifier); + var response = await get(Uri.parse(imageUrl)); + var firstPath = externalDir.path + "/images"; + var filePathAndName = externalDir.path + '/images/$id.jpg'; + await Directory(firstPath).create(recursive: true); + File file2 = new File(filePathAndName); + file2.writeAsBytesSync(response.bodyBytes); + return filePathAndName; + } + + void _deleteImage(String filePath) async { + try { + if (await File(filePath).exists()) { + await File(filePath).delete(); + print('File removed successfully: $filePath'); + } + } catch (e) {} + } } diff --git a/lib/src/screens/podcast/view/local_podcast_episode.dart b/lib/src/screens/podcast/view/local_podcast_episode.dart index bb8332fc..e9dd00da 100644 --- a/lib/src/screens/podcast/view/local_podcast_episode.dart +++ b/lib/src/screens/podcast/view/local_podcast_episode.dart @@ -1,3 +1,6 @@ +import 'dart:developer'; +import 'dart:io'; + import 'package:acela/src/models/podcast/podcast_episodes.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; @@ -9,7 +12,8 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class LocalPodcastEpisode extends StatelessWidget { - const LocalPodcastEpisode({Key? key, required this.appData}) : super(key: key); + const LocalPodcastEpisode({Key? key, required this.appData}) + : super(key: key); final HiveUserData appData; @override @@ -22,7 +26,7 @@ class LocalPodcastEpisode extends StatelessWidget { bottom: TabBar( tabs: [ Tab(text: 'Offline Episode'), - Tab(text: 'Liked Episode'), + Tab(text: 'Bookmarked Episode'), ], ), ), @@ -38,20 +42,25 @@ class LocalPodcastEpisode extends StatelessWidget { } class LocalEpisodeListView extends StatelessWidget { - const LocalEpisodeListView({Key? key, required this.isOffline}) : super(key: key); + const LocalEpisodeListView({Key? key, required this.isOffline}) + : super(key: key); final bool isOffline; @override Widget build(BuildContext context) { final controller = context.read(); - List items = controller.likedOrOfflinepodcastEpisodes(isOffline: isOffline); + List items = + controller.likedOrOfflinepodcastEpisodes(isOffline: isOffline); if (items.isEmpty) - return Center(child: Text("${isOffline ? "Offline" : "Liked"} Podcast Episode is Empty")); + return Center( + child: Text( + "${isOffline ? "Offline" : "Liked"} Podcast Episode is Empty")); else return ListView.separated( itemBuilder: (c, index) { PodcastEpisode item = items[index]; + log(item.image!); return Dismissible( key: Key(item.id.toString()), background: Center(child: Text("Delete")), @@ -59,7 +68,8 @@ class LocalEpisodeListView extends StatelessWidget { if (isOffline) { controller.deleteOfflinePodcastEpisode(item); } else { - controller.storeLikedPodcastEpisodeLocally(item, forceRemove: true); + controller.storeLikedPodcastEpisodeLocally(item, + forceRemove: true); } }, child: podcastEpisodeListItem(item, context, controller)); @@ -69,10 +79,13 @@ class LocalEpisodeListView extends StatelessWidget { ); } - ListTile podcastEpisodeListItem(PodcastEpisode item, BuildContext context, PodcastController controller) { + ListTile podcastEpisodeListItem( + PodcastEpisode item, BuildContext context, PodcastController controller) { String url = item.enclosureUrl ?? ""; if (isOffline) { - url = Uri.parse(controller.getOfflineUrl(item.enclosureUrl ?? "", item.id!)).path; + url = + Uri.parse(controller.getOfflineUrl(item.enclosureUrl ?? "", item.id!)) + .path; item.enclosureUrl = '$url'; } return ListTile( @@ -112,11 +125,14 @@ class LocalEpisodeListView extends StatelessWidget { width: 30, decoration: BoxDecoration( color: Colors.grey, - image: DecorationImage( - image: NetworkImage( - item.image ?? "", - ), - fit: BoxFit.cover)), + image: (isOffline && !item.image!.startsWith('http')) + ? DecorationImage( + image: FileImage(File(item.image!)), fit: BoxFit.cover) + : DecorationImage( + image: NetworkImage( + item.image ?? "", + ), + )), ), title: Text( item.title ?? '', diff --git a/lib/src/screens/podcast/view/podcast_trending.dart b/lib/src/screens/podcast/view/podcast_trending.dart index 08b180b1..372d55bd 100644 --- a/lib/src/screens/podcast/view/podcast_trending.dart +++ b/lib/src/screens/podcast/view/podcast_trending.dart @@ -238,8 +238,8 @@ class _PodCastTrendingScreenState extends State }, ); var favourites = FabOverItemData( - displayName: 'Favourites', - icon: Icons.favorite, + displayName: 'Bookmarks', + icon: Icons.bookmarks, onTap: () { setState(() { isMenuOpen = false; diff --git a/lib/src/screens/podcast/widgets/favourite.dart b/lib/src/screens/podcast/widgets/favourite.dart index d4e5572f..965c600e 100644 --- a/lib/src/screens/podcast/widgets/favourite.dart +++ b/lib/src/screens/podcast/widgets/favourite.dart @@ -47,7 +47,7 @@ class _FavouriteWidgetState extends State { constraints: widget.disablePadding ? BoxConstraints() : null, padding: widget.disablePadding ? EdgeInsets.zero : null, icon: Icon( - isLiked ? Icons.favorite : Icons.favorite_border, + isLiked ? Icons.bookmark : Icons.bookmark_border, size: widget.iconSize, color: widget.iconColor, ), diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart index 840f59fa..51139954 100644 --- a/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart @@ -37,7 +37,7 @@ class _DownloadPodcastButtonState extends State { IsolateNameServer.registerPortWithName( _port.sendPort, 'downloader_send_port'); - _port.listen((dynamic data) { + _port.listen((dynamic data) async { // String id = data[0]; // DownloadTaskStatus statuss = (data[1]); int progress = data[2]; @@ -46,7 +46,7 @@ class _DownloadPodcastButtonState extends State { if (progress == 100 && status == DownloadStatus.downloading && taskId != null) { - podcastController.storeOfflinePodcastLocally(widget.episode); + podcastController.storeOfflinePodcastLocally(widget.episode); setState(() { status = DownloadStatus.downloaded; }); @@ -74,12 +74,12 @@ class _DownloadPodcastButtonState extends State { status = DownloadStatus.download; taskId = null; }); - }else { - setState(() { - _setStatusOnEpisodeChange(); - }); + } else { + setState(() { + _setStatusOnEpisodeChange(); + }); + } } - } super.didUpdateWidget(oldWidget); } diff --git a/lib/src/screens/user_channel_screen/user_channel_screen.dart b/lib/src/screens/user_channel_screen/user_channel_screen.dart index 8f4feddf..f8147a3a 100644 --- a/lib/src/screens/user_channel_screen/user_channel_screen.dart +++ b/lib/src/screens/user_channel_screen/user_channel_screen.dart @@ -12,8 +12,10 @@ import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; class UserChannelScreen extends StatefulWidget { - const UserChannelScreen({Key? key, required this.owner}) : super(key: key); + const UserChannelScreen( {Key? key, required this.owner, this.onPop}) + : super(key: key); final String owner; + final VoidCallback? onPop; @override _UserChannelScreenState createState() => _UserChannelScreenState(); @@ -52,6 +54,12 @@ class _UserChannelScreenState extends State }); } + @override + void deactivate() { + if (widget.onPop != null) widget.onPop!(); + super.deactivate(); + } + @override void dispose() { super.dispose(); diff --git a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart index 8c29204b..3605dab3 100644 --- a/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart +++ b/lib/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:developer'; import 'dart:io'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/image_resolution_provider.dart'; @@ -17,7 +16,9 @@ import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/hive_upvote_dialog.dart'; import 'package:acela/src/screens/video_details_screen/new_video_details_info.dart'; import 'package:acela/src/screens/video_details_screen/comment/video_details_comments.dart'; +import 'package:acela/src/utils/routes/routes.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; +import 'package:acela/src/widgets/box_loading/video_detail_feed_loader.dart'; import 'package:acela/src/widgets/box_loading/video_feed_loader.dart'; import 'package:acela/src/widgets/cached_image.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart'; @@ -26,6 +27,7 @@ import 'package:better_player/better_player.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:wakelock/wakelock.dart'; import 'package:timeago/timeago.dart' as timeago; @@ -35,12 +37,16 @@ import 'package:http/http.dart' as http; class NewVideoDetailsScreen extends StatefulWidget { const NewVideoDetailsScreen( {Key? key, - required this.item, - required this.appData, - this.betterPlayerController}); - - final GQLFeedItem item; - final HiveUserData appData; + this.item, + this.betterPlayerController, + required this.author, + required this.permlink, + this.onPop}); + + final GQLFeedItem? item; + final String author; + final String permlink; + final VoidCallback? onPop; final BetterPlayerController? betterPlayerController; @override @@ -49,19 +55,22 @@ class NewVideoDetailsScreen extends StatefulWidget { class _NewVideoDetailsScreenState extends State { late BetterPlayerController _betterPlayerController; + late GQLFeedItem item; + bool isLoadingVideo = true; HivePostInfoPostResultBody? postInfo; var selectedChip = 0; late final VideoSettingProvider videoSettingProvider; - + late HiveUserData appData; List suggestions = []; bool isSuggestionsLoading = true; @override void initState() { + appData = context.read(); videoSettingProvider = context.read(); super.initState(); Wakelock.enable(); - loadRatio(); + loadDataAndVideo(); loadHiveInfo(); loadSuggestions(); } @@ -76,11 +85,18 @@ class _NewVideoDetailsScreenState extends State { Wakelock.disable(); } + @override + void deactivate() { + changeControlsVisibility(false); + if (widget.onPop != null) widget.onPop!(); + super.deactivate(); + } + void loadSuggestions() async { var items = await GQLCommunicator().getRelated( - widget.item.author?.username ?? 'sagarkothari88', - widget.item.permlink ?? 'ctbtwcxbbd', - widget.appData.language, + widget.author, + widget.permlink, + appData.language, ); setState(() { suggestions = items; @@ -92,7 +108,7 @@ class _NewVideoDetailsScreenState extends State { setState(() { postInfo = null; }); - var data = await fetchHiveInfoForThisVideo(widget.appData.rpc); + var data = await fetchHiveInfoForThisVideo(appData.rpc); setState(() { postInfo = data; }); @@ -106,8 +122,8 @@ class _NewVideoDetailsScreenState extends State { "jsonrpc": "2.0", "method": "bridge.get_discussion", "params": { - "author": widget.item.author?.username ?? 'sagarkothari88', - "permlink": widget.item.permlink ?? 'ctbtwcxbbd', + "author": widget.author, + "permlink": widget.permlink, "observer": "" } }); @@ -117,8 +133,7 @@ class _NewVideoDetailsScreenState extends State { var result = HivePostInfo.fromJsonString(string) .result .resultData - .where((element) => - element.permlink == (widget.item.permlink ?? 'ctbtwcxbbd')) + .where((element) => element.permlink == (widget.permlink)) .first; return result; } else { @@ -133,7 +148,7 @@ class _NewVideoDetailsScreenState extends State { builder: (context, value, child) { return CachedImage( imageUrl: Utilities.getProxyImage( - value, (widget.item.spkvideo?.thumbnailUrl ?? '')), + value, (item.spkvideo?.thumbnailUrl ?? '')), imageHeight: 230, imageWidth: double.infinity, ); @@ -170,12 +185,12 @@ class _NewVideoDetailsScreenState extends State { ); BetterPlayerDataSource dataSource = BetterPlayerDataSource( BetterPlayerDataSourceType.network, - (widget.item.isVideo) + (item.isVideo) ? Platform.isAndroid ? url.replaceAll("/manifest.m3u8", "/480p/index.m3u8") : url - : widget.item.playUrl!, - videoFormat: widget.item.isVideo + : item.playUrl!, + videoFormat: item.isVideo ? BetterPlayerVideoFormat.hls : BetterPlayerVideoFormat.other, ); @@ -197,17 +212,28 @@ class _NewVideoDetailsScreenState extends State { } } - void loadRatio() async { + void loadDataAndVideo() async { + if (widget.item != null) { + item = widget.item!; + isLoadingVideo = false; + } else { + var data = await GQLCommunicator() + .getVideoDetails(widget.author, widget.permlink); + setState(() { + item = data; + isLoadingVideo = false; + }); + } if (widget.betterPlayerController != null) { _betterPlayerController = widget.betterPlayerController!; changeControlsVisibility(true); } else { - if (widget.item.isVideo) { + if (item.isVideo) { setupVideo( - widget.item.videoV2M3U8(widget.appData), + item.videoV2M3U8(appData), ); } else { - setupVideo(widget.item.playUrl!); + setupVideo(item.playUrl!); } if (videoSettingProvider.isMuted) { @@ -227,7 +253,7 @@ class _NewVideoDetailsScreenState extends State { debugPrint('position is $position'); const platform = MethodChannel('com.example.acela/auth'); await platform.invokeMethod('playFullscreen', { - 'url': widget.item.videoV2M3U8(widget.appData), + 'url': item.videoV2M3U8(appData), 'seconds': seconds, }); } @@ -235,7 +261,7 @@ class _NewVideoDetailsScreenState extends State { Widget _videoPlayerStack(double screenHeight, bool isGridView) { return SliverToBoxAdapter( child: Hero( - tag: '${widget.item.author}/${widget.item.permlink}', + tag: '${item.author}/${item.permlink}', child: SizedBox( height: isGridView ? screenHeight * 0.4 : 230, child: Stack( @@ -296,9 +322,8 @@ class _NewVideoDetailsScreenState extends State { } Widget _userInfo() { - String timeInString = widget.item.createdAt != null - ? "${timeago.format(widget.item.createdAt!)}" - : ""; + String timeInString = + item.createdAt != null ? "${timeago.format(item.createdAt!)}" : ""; return SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.only(top: 10.0, bottom: 5), @@ -307,21 +332,20 @@ class _NewVideoDetailsScreenState extends State { dense: true, splashColor: Colors.transparent, onTap: () { - var screen = UserChannelScreen( - owner: widget.item.author?.username ?? "sagarkothari88"); - var route = MaterialPageRoute(builder: (_) => screen); - Navigator.of(context).push(route); + context.pushNamed(Routes.userView, pathParameters: { + 'author': item.author?.username ?? "sagarkothari88" + }); }, leading: ClipOval( child: CachedImage( imageUrl: - 'https://images.hive.blog/u/${widget.item.author?.username ?? 'sagarkothari88'}/avatar', + 'https://images.hive.blog/u/${item.author?.username ?? 'sagarkothari88'}/avatar', imageHeight: 40, imageWidth: 40, ), ), title: Text( - widget.item.title ?? 'No title', + item.title ?? 'No title', style: TextStyle( color: Theme.of(context).primaryColorLight, fontWeight: FontWeight.bold, @@ -331,7 +355,7 @@ class _NewVideoDetailsScreenState extends State { children: [ Expanded( child: Text( - widget.item.author?.username ?? "sagarkothari88", + item.author?.username ?? "sagarkothari88", maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(color: Theme.of(context).primaryColorLight), @@ -362,12 +386,12 @@ class _NewVideoDetailsScreenState extends State { List voters = []; bool currentUserPresentInVoters = false; if (postInfo != null) { - if (widget.appData.username != null) { + if (appData.username != null) { int userNameInVotesIndex = postInfo!.activeVotes - .indexWhere((element) => element.voter == widget.appData.username); + .indexWhere((element) => element.voter == appData.username); if (userNameInVotesIndex != -1) { currentUserPresentInVoters = true; - voters.add(widget.appData.username!); + voters.add(appData.username!); for (int i = 0; i < postInfo!.activeVotes.length; i++) { if (i != userNameInVotesIndex) { voters.add(postInfo!.activeVotes[i].voter); @@ -447,7 +471,7 @@ class _NewVideoDetailsScreenState extends State { void upvotePressed() { if (postInfo == null) return; - if (widget.appData.username == null) { + if (appData.username == null) { showAdaptiveActionSheet( context: context, title: const Text('You are not logged in. Please log in to upvote.'), @@ -458,7 +482,7 @@ class _NewVideoDetailsScreenState extends State { leading: Icon(Icons.login), onPressed: (c) { Navigator.of(c).pop(); - var screen = HiveAuthLoginScreen(appData: widget.appData); + var screen = HiveAuthLoginScreen(appData: appData); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(c).push(route); }), @@ -469,7 +493,7 @@ class _NewVideoDetailsScreenState extends State { } if (postInfo!.activeVotes .map((e) => e.voter) - .contains(widget.appData.username ?? 'sagarkothari88') == + .contains(appData.username ?? 'sagarkothari88') == true) { showError('You have already voted for this video'); } @@ -478,13 +502,13 @@ class _NewVideoDetailsScreenState extends State { isScrollControlled: true, builder: (context) { return HiveUpvoteDialog( - author: widget.item.author?.username ?? 'sagarkothari88', - permlink: widget.item.permlink ?? 'ctbtwcxbbd', - username: widget.appData.username ?? "", - accessToken: widget.appData.accessToken, - postingAuthority: widget.appData.postingAuthority, - hasKey: widget.appData.keychainData?.hasId ?? "", - hasAuthKey: widget.appData.keychainData?.hasAuthKey ?? "", + author: item.author?.username ?? 'sagarkothari88', + permlink: item.permlink ?? 'ctbtwcxbbd', + username: appData.username ?? "", + accessToken: appData.accessToken, + postingAuthority: appData.postingAuthority, + hasKey: appData.keychainData?.hasId ?? "", + hasAuthKey: appData.keychainData?.hasAuthKey ?? "", activeVotes: postInfo!.activeVotes, onClose: () {}, onDone: () { @@ -500,11 +524,11 @@ class _NewVideoDetailsScreenState extends State { context, MaterialPageRoute( builder: (context) => NewVideoDetailsInfo( - appData: widget.appData, - item: widget.item, + appData: appData, + item: item, ), )); - _playVideoAfterPush(); + _playVideoAfterPush(); } void seeCommentsPressed() { @@ -512,11 +536,11 @@ class _NewVideoDetailsScreenState extends State { MaterialPageRoute( builder: (context) { return VideoDetailsComments( - author: widget.item.author?.username ?? 'sagarkothari88', - permlink: widget.item.permlink ?? 'ctbtwcxbbd', - rpc: widget.appData.rpc, - appData: widget.appData, - item: widget.item, + author: item.author?.username ?? 'sagarkothari88', + permlink: item.permlink ?? 'ctbtwcxbbd', + rpc: appData.rpc, + appData: appData, + item: item, ); }, ), @@ -532,8 +556,8 @@ class _NewVideoDetailsScreenState extends State { Widget _actionBar(double width) { final VideoFavoriteProvider provider = VideoFavoriteProvider(); Color color = Theme.of(context).primaryColorLight; - String votes = "${widget.item.stats?.numVotes ?? 0}"; - String comments = "${widget.item.stats?.numComments ?? 0}"; + String votes = "${item.stats?.numVotes ?? 0}"; + String comments = "${item.stats?.numComments ?? 0}"; return SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5), @@ -586,19 +610,19 @@ class _NewVideoDetailsScreenState extends State { IconButton( onPressed: () { Share.share( - 'https://3speak.tv/watch?v=${widget.item.author?.username ?? 'sagarkothari88'}/${widget.item.permlink}'); + 'https://3speak.tv/watch?v=${item.author?.username ?? 'sagarkothari88'}/${item.permlink}'); }, icon: Icon(Icons.share, color: color), ), FavouriteWidget( toastType: "Video", iconColor: color, - isLiked: provider.isLikedVideoPresentLocally(widget.item), + isLiked: provider.isLikedVideoPresentLocally(item), onAdd: () { - provider.storeLikedVideoLocally(widget.item); + provider.storeLikedVideoLocally(item); }, onRemove: () { - provider.storeLikedVideoLocally(widget.item); + provider.storeLikedVideoLocally(item); }) ], ), @@ -607,10 +631,10 @@ class _NewVideoDetailsScreenState extends State { } bool isUserVoted() { - if (widget.appData.username != null) { + if (appData.username != null) { if (postInfo != null && postInfo!.activeVotes.isNotEmpty) { int index = postInfo!.activeVotes - .indexWhere((element) => element.voter == widget.appData.username); + .indexWhere((element) => element.voter == appData.username); if (index != -1) { return true; } @@ -620,8 +644,7 @@ class _NewVideoDetailsScreenState extends State { } Widget _chipList() { - List tags = - widget.item.tags ?? ['threespeak', 'video', 'threeshorts']; + List tags = item.tags ?? ['threespeak', 'video', 'threeshorts']; return SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.only(bottom: 15.0, top: 5), @@ -688,15 +711,24 @@ class _NewVideoDetailsScreenState extends State { return PopScope( onPopInvoked: (value) { changeControlsVisibility(false); + if (widget.onPop != null) widget.onPop!(); }, child: Scaffold( body: SafeArea( child: CustomScrollView( slivers: [ - _videoPlayerStack(height, isGridView), - _userInfo(), - _actionBar(width), - _chipList(), + !isLoadingVideo + ? _videoPlayerStack(height, isGridView) + : sliverSizedBox(), + !isLoadingVideo ? _userInfo() : sliverSizedBox(), + !isLoadingVideo ? _actionBar(width) : sliverSizedBox(), + !isLoadingVideo ? _chipList() : sliverSizedBox(), + SliverVisibility( + visible: isLoadingVideo, + sliver: SliverToBoxAdapter( + child: VideoDetailFeedLoader(isGridView: isGridView), + ), + ), isSuggestionsLoading ? VideoFeedLoader( isSliver: true, @@ -711,8 +743,14 @@ class _NewVideoDetailsScreenState extends State { ); } + Widget sliverSizedBox() { + return const SliverToBoxAdapter( + child: SizedBox.shrink(), + ); + } + Widget _sliverGridView() { - return FeedItemGridWidget(items: suggestions, appData: widget.appData); + return FeedItemGridWidget(items: suggestions, appData: appData); } SliverList _sliverListView() { @@ -734,7 +772,7 @@ class _NewVideoDetailsScreenState extends State { onTap: () {}, onUserTap: () {}, item: item, - appData: widget.appData, + appData: appData, ); }, childCount: suggestions.length, diff --git a/lib/src/screens/video_details_screen/video_details_screen.dart b/lib/src/screens/video_details_screen/video_details_screen.dart index 4839202b..a1a8f5f6 100644 --- a/lib/src/screens/video_details_screen/video_details_screen.dart +++ b/lib/src/screens/video_details_screen/video_details_screen.dart @@ -9,10 +9,10 @@ import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_recommendation_models/video_recommendation.dart'; -import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/comment/hive_comment_dialog.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/utils/routes/routes.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/list_tile_video.dart'; @@ -22,6 +22,7 @@ import 'package:better_player/better_player.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:go_router/go_router.dart'; import 'package:http/http.dart' as http; import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; @@ -60,8 +61,8 @@ class _VideoDetailsScreenState extends State { void onUserTap() { _betterPlayerController.pause(); - Navigator.of(context).push(MaterialPageRoute( - builder: (c) => UserChannelScreen(owner: widget.vm.author))); + context.pushNamed(Routes.userView, + pathParameters: {'author': widget.vm.author}); } // used when there is an error state in loading video info @@ -143,8 +144,7 @@ class _VideoDetailsScreenState extends State { var data = snapshot.data as HivePostInfoPostResultBody; var upVotes = data.activeVotes.where((e) => e.rshares > 0).length; var downVotes = data.activeVotes.where((e) => e.rshares < 0).length; - String priceAndVotes = - "👍 $upVotes · 👎 $downVotes"; + String priceAndVotes = "👍 $upVotes · 👎 $downVotes"; return Container( margin: const EdgeInsets.all(10), child: Column( @@ -157,12 +157,8 @@ class _VideoDetailsScreenState extends State { width: 40, url: server.userOwnerThumb(details.owner)), onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (c) => - UserChannelScreen(owner: details.owner), - ), - ); + context.pushNamed(Routes.userView, + pathParameters: {'author': details.owner}); }, ), SizedBox(width: 10), @@ -170,12 +166,8 @@ class _VideoDetailsScreenState extends State { child: Text(details.owner, style: Theme.of(context).textTheme.bodyLarge), onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (c) => - UserChannelScreen(owner: details.owner), - ), - ); + context.pushNamed(Routes.userView, + pathParameters: {'author': details.owner}); }), SizedBox(width: 10), Spacer(), @@ -325,8 +317,7 @@ class _VideoDetailsScreenState extends State { ? IconButton( onPressed: () { var ipfsHash = details.playUrl - .replaceAll( - IpfsNodeProvider().nodeUrl, "") + .replaceAll(IpfsNodeProvider().nodeUrl, "") .replaceAll("/manifest.m3u8", ""); Share.share( "Copy this IPFS Hash & Pin it on your system - $ipfsHash"); @@ -558,8 +549,8 @@ class _VideoDetailsScreenState extends State { subtitle: "", onUserTap: () { _betterPlayerController.pause(); - Navigator.of(context).push(MaterialPageRoute( - builder: (c) => UserChannelScreen(owner: item.owner))); + context + .pushNamed(Routes.userView, pathParameters: {'author': item.owner}); }, user: item.owner, permlink: item.mediaid, diff --git a/lib/src/utils/graphql/gql_communicator.dart b/lib/src/utils/graphql/gql_communicator.dart index 07e4367f..deb36702 100644 --- a/lib/src/utils/graphql/gql_communicator.dart +++ b/lib/src/utils/graphql/gql_communicator.dart @@ -9,10 +9,9 @@ import 'package:http/http.dart' as http; import 'package:http/http.dart'; class GQLCommunicator { - static const defaultGQLServer = - "union.us-02.infra.3speak.tv"; + static const defaultGQLServer = "union.us-02.infra.3speak.tv"; // static const gqlServer = "https://union.us-02.infra.3speak.tv/api/v2/graphql"; -static const dataQuery = + static const dataQuery = "{\n items {\n created_at\n title\n ... on HivePost {\n permlink\n lang\n title\n tags\n spkvideo\n stats {\n num_comments\n num_votes\n total_hive_reward\n }\n author {\n username\n }\n json_metadata {\n raw\n }\n }\n }\n }\n}"; Future> getGQLFeed(String operation, String query) async { @@ -189,31 +188,64 @@ static const dataQuery = "query UserChannelFeed {\n socialFeed($spkVideoQuery$feedOptionsQuery$paginationQuery)\n$dataQuery"); } - Future> getHiveComments(String userName,String permLink) async { - try{ + Future> getHiveComments( + String userName, String permLink) async { + try { + var headers = { + 'Connection': 'keep-alive', + 'content-type': 'application/json', + }; + var body = json.encode({ + "query": + "query GetComments {\n socialPost(author: \"$userName\", permlink: \"$permLink\") {\n ... on HivePost {\n children {\n ... on HivePost {\n body\n permlink\n created_at\n author {\n username\n }\n stats {\n num_votes\n }\n children {\n ... on HivePost {\n body\n permlink\n created_at\n author {\n username\n }\n stats {\n num_votes\n }\n }\n children {\n ... on HivePost {\n body\n permlink\n created_at\n author {\n username\n }\n stats {\n num_votes\n }\n }\n }\n }\n }\n }\n body\n }\n }\n}", + "operationName": "GetComments", + "extensions": {} + }); + http.Response response = await post( + Uri.parse('https://union.us-02.infra.3speak.tv/api/v2/graphql'), + headers: headers, + body: body); + + if (response.statusCode == 200) { + var string = response.body; + return GQLHiveCommentReponse.fromRawJson(string) + .data + .socialPost + .children ?? + []; + } else { + throw response.reasonPhrase ?? 'Error occurred'; + } + } catch (e) { + throw e; + } + } + + Future getVideoDetails(String author,String permlink) async { var headers = { 'Connection': 'keep-alive', 'content-type': 'application/json', - }; - var body = json.encode({ - "query": - "query GetComments {\n socialPost(author: \"$userName\", permlink: \"$permLink\") {\n ... on HivePost {\n children {\n ... on HivePost {\n body\n permlink\n created_at\n author {\n username\n }\n stats {\n num_votes\n }\n children {\n ... on HivePost {\n body\n permlink\n created_at\n author {\n username\n }\n stats {\n num_votes\n }\n }\n children {\n ... on HivePost {\n body\n permlink\n created_at\n author {\n username\n }\n stats {\n num_votes\n }\n }\n }\n }\n }\n }\n body\n }\n }\n}", - "operationName": "GetComments", - "extensions": {} - }); - http.Response response = - await post(Uri.parse('https://union.us-02.infra.3speak.tv/api/v2/graphql'),headers: headers,body:body ); + const storage = FlutterSecureStorage(); + String union = + await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; + String gqlServer = "https://$union/api/v2/graphql"; + var request = http.Request('POST', Uri.parse(gqlServer)); + var query = + "query MyQuery {\n socialPost(author: \"edmundochauran\", permlink: \"dbgmwaox\") {\n ... on HivePost {\n spkvideo\n title\n lang\n json_metadata {\n raw\n }\n created_at\n tags\n author {\n username\n }\n permlink\n stats {\n num_comments\n num_votes\n total_hive_reward\n }\n community\n body\n app_metadata\n }\n }\n}"; + request.body = json + .encode({"query": query, "operationName": "MyQuery", "extensions": {}}); + request.headers.addAll(headers); + + http.StreamedResponse response = await request.send(); if (response.statusCode == 200) { - var string = response.body; - return GQLHiveCommentReponse.fromRawJson(string).data.socialPost.children ?? []; + var string = await response.stream.bytesToString(); + var responseData = VideoDetailsFeed.fromRawJson(string); + return responseData.item; } else { + print(response.reasonPhrase); throw response.reasonPhrase ?? 'Error occurred'; } } - catch(e){ - throw e; - } - } } diff --git a/lib/src/utils/graphql/models/trending_feed_response.dart b/lib/src/utils/graphql/models/trending_feed_response.dart index cdb8b1a3..03279b07 100644 --- a/lib/src/utils/graphql/models/trending_feed_response.dart +++ b/lib/src/utils/graphql/models/trending_feed_response.dart @@ -133,8 +133,10 @@ class GQLFeedItem { String toRawJson() => json.encode(toJson()); factory GQLFeedItem.fromJson(Map json) => GQLFeedItem( - playUrl: json['json_metadata']?['raw']?['video']?['info']?['video_v2'] , - isVideo: json['json_metadata']?['raw']?['video']?['info']?['video_v2']?.endsWith('.m3u8') ?? true, + playUrl: json['json_metadata']?['raw']?['video']?['info']?['video_v2'], + isVideo: json['json_metadata']?['raw']?['video']?['info']?['video_v2'] + ?.endsWith('.m3u8') ?? + true, stats: json["stats"] == null ? null : GQLFeedItemStats.fromJson(json["stats"]), @@ -163,7 +165,6 @@ class GQLFeedItem { json["children"]!.map((x) => GQLFeedItemChild.fromJson(x))), ); - Map toJson() => { "stats": stats?.toJson(), "spkvideo": spkvideo?.toJson(), @@ -465,3 +466,21 @@ class GQLFeedItemStats { "num_comments": numComments, }; } + +class VideoDetailsFeed { + final GQLFeedItem item; + + VideoDetailsFeed({required this.item}); + + factory VideoDetailsFeed.fromRawJson(String str) => + VideoDetailsFeed.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory VideoDetailsFeed.fromJson(Map json) => + VideoDetailsFeed( + item: GQLFeedItem.fromJson(json['data']['socialPost']), + ); + + Map toJson() => {"item": item.toJson()}; +} diff --git a/lib/src/utils/routes/app_router.dart b/lib/src/utils/routes/app_router.dart new file mode 100644 index 00000000..510f3bab --- /dev/null +++ b/lib/src/utils/routes/app_router.dart @@ -0,0 +1,62 @@ +import 'package:acela/src/models/navigation_models/new_video_detail_screen_navigation_model.dart'; +import 'package:acela/src/screens/home_screen/default_screen.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; +import 'package:acela/src/screens/video_details_screen/new_video_details/new_video_details_screen.dart'; +import 'package:acela/src/utils/routes/routes.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class AppRouter { + + static GoRouter router = GoRouter(routes: routes()); + + static List routes() { + return [ + GoRoute( + path: '/', + name: Routes.initialView, + builder: (context, state) => DefaultView()), + GoRoute( + path: '/${Routes.videoDetailsView}/:author/:permlink', + name: Routes.videoDetailsView, + builder: (context, state) { + NewVideoDetailScreenNavigationParameter? parameters = + (state.extra) as NewVideoDetailScreenNavigationParameter?; + return NewVideoDetailsScreen( + item: parameters?.item, + onPop: parameters?.onPop, + betterPlayerController: parameters?.betterPlayerController, + author: state.pathParameters['author']!, + permlink: state.pathParameters['permlink']!, + ); + }, + redirect: (context, state) { + final author = state.pathParameters['author']; + final permlink = state.pathParameters['permlink']; + if (author == null || permlink == null) { + return '/'; + } + return null; + }, + ), + GoRoute( + path: '/${Routes.userView}/:author', + name: Routes.userView, + builder: (context, state) { + return UserChannelScreen( + owner: state.pathParameters['author']!, + onPop: (state.extra) as VoidCallback?, + ); + }, + redirect: (context, state) { + final author = state.pathParameters['author']; + if (author == null) { + return '/'; + } + return null; + }, + ), + + ]; + } +} diff --git a/lib/src/utils/routes/routes.dart b/lib/src/utils/routes/routes.dart new file mode 100644 index 00000000..e505b598 --- /dev/null +++ b/lib/src/utils/routes/routes.dart @@ -0,0 +1,6 @@ +class Routes { + static const String initialView = 'initial'; + static const String userView = 'user'; + static const String videoDetailsView = 'videoDetails'; + +} diff --git a/lib/src/widgets/box_loading/video_detail_feed_loader.dart b/lib/src/widgets/box_loading/video_detail_feed_loader.dart new file mode 100644 index 00000000..adf8fc07 --- /dev/null +++ b/lib/src/widgets/box_loading/video_detail_feed_loader.dart @@ -0,0 +1,85 @@ +import 'package:acela/src/widgets/box_loading/box_loading.dart'; +import 'package:acela/src/widgets/box_loading/box_trail.dart'; +import 'package:flutter/material.dart'; + +class VideoDetailFeedLoader extends StatelessWidget { + const VideoDetailFeedLoader({Key? key, required this.isGridView}) + : super(key: key); + + final bool isGridView; + + @override + Widget build(BuildContext context) { + final screenHeight = MediaQuery.of(context).size.height; + final screenWidth = MediaQuery.of(context).size.width; + return BoxLoadingIndicator( + child: Column( + children: [ + BoxTrail( + borderRadius: 0, + height: isGridView ? screenHeight * 0.4 : 230, + ), + Padding( + padding: const EdgeInsets.only(top: 10.0, bottom: 5), + child: ListTile( + contentPadding: EdgeInsets.only(top: 0, left: 15, right: 15), + dense: true, + leading: BoxTrail( + height: 40, + width: 40, + shape: BoxShape.circle, + ), + title: BoxTrail( + width: screenWidth * 0.8, + ), + subtitle: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + BoxTrail( + width: screenWidth * 0.4, + ), + BoxTrail(width: 80), + ], + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: List.generate( + 5, + (index) => BoxTrail( + height: 35, + width: 35, + shape: BoxShape.circle, + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(bottom: 15.0, top: 15), + child: SizedBox( + height: 33, + child: ListView.builder( + padding: EdgeInsets.symmetric(horizontal: 8), + scrollDirection: Axis.horizontal, + itemCount: 5, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.only(right: 8), + child: BoxTrail( + width: 130, + borderRadius: 18, + ), + ); + }, + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/widgets/gql_feed_list_item.dart b/lib/src/widgets/gql_feed_list_item.dart index b4844835..bc7e2896 100644 --- a/lib/src/widgets/gql_feed_list_item.dart +++ b/lib/src/widgets/gql_feed_list_item.dart @@ -3,11 +3,12 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/video_details_screen/new_video_details_info.dart'; import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; -import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; +import 'package:acela/src/utils/routes/routes.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:timeago/timeago.dart' as timeago; @@ -53,9 +54,7 @@ class _GQLFeedListItemWidgetState extends State { url: server.userOwnerThumb(author), ), onTap: () { - var screen = UserChannelScreen(owner: author); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); + context.pushNamed(Routes.userView, pathParameters: {'author': author}); }, ), title: Padding( @@ -67,9 +66,7 @@ class _GQLFeedListItemWidgetState extends State { InkWell( child: Text('👤 $author'), onTap: () { - var screen = UserChannelScreen(owner: author); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); + context.pushNamed(Routes.userView, pathParameters: {'author': author}); }, ), SizedBox(width: 10), diff --git a/lib/src/widgets/story_player.dart b/lib/src/widgets/story_player.dart index e9bd5180..eb4acd6f 100644 --- a/lib/src/widgets/story_player.dart +++ b/lib/src/widgets/story_player.dart @@ -1,6 +1,5 @@ import 'dart:convert'; import 'dart:developer'; - import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/video_setting_provider.dart'; import 'package:acela/src/screens/podcast/widgets/favourite.dart'; @@ -10,16 +9,17 @@ import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; import 'package:acela/src/models/hive_post_info/hive_post_info.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/login/ha_login_screen.dart'; -import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/hive_upvote_dialog.dart'; import 'package:acela/src/screens/video_details_screen/new_video_details_info.dart'; import 'package:acela/src/screens/video_details_screen/comment/video_details_comments.dart'; import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/utils/routes/routes.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:better_player/better_player.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; import 'package:http/http.dart' as http; @@ -398,7 +398,7 @@ class _StoryPlayerState extends State { Visibility( visible: !controlsVisible, child: Padding( - padding: const EdgeInsets.only(left : 5.0), + padding: const EdgeInsets.only(left: 5.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.end, @@ -448,11 +448,10 @@ class _StoryPlayerState extends State { ], ), onPressed: () { - var screen = UserChannelScreen( - owner: - widget.item.author?.username ?? 'sagarkothari88'); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); + context.pushNamed(Routes.userView, pathParameters: { + 'author': + widget.item.author?.username ?? 'sagarkothari88' + }); }, ), ), diff --git a/pubspec.lock b/pubspec.lock index 310e42f1..0acdf5f4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -746,6 +746,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: "170c46e237d6eb0e6e9f0e8b3f56101e14fb64f787016e42edd74c39cf8b176a" + url: "https://pub.dev" + source: hosted + version: "13.2.0" graphs: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9420e13d..977cee47 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -93,6 +93,7 @@ dependencies: firebase_core: ^2.25.4 firebase_analytics: ^10.8.5 firebase_crashlytics: ^3.4.14 + go_router: ^13.2.0 dev_dependencies: flutter_test: From 0779adfe06a74e9179c98f0c145d9ddad57e4807 Mon Sep 17 00:00:00 2001 From: sagar Date: Thu, 14 Mar 2024 18:10:54 +0530 Subject: [PATCH 383/466] bottomnav bar, improvements and bug fix --- .../widgets/bottom_nav_bar.dart | 232 ++++++++++++++++++ .../screens/home_screen/new_home_screen.dart | 180 +++----------- lib/src/screens/login/ha_login_screen.dart | 12 - .../account_settings_screen.dart | 6 - .../screens/my_account/my_account_screen.dart | 17 +- lib/src/screens/settings/settings_screen.dart | 6 - .../video/widgets/work_type_widget.dart | 26 +- lib/src/utils/communicator.dart | 4 +- 8 files changed, 301 insertions(+), 182 deletions(-) create mode 100644 lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart new file mode 100644 index 00000000..4eff8627 --- /dev/null +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart @@ -0,0 +1,232 @@ +import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/home_screen/video_upload_sheet.dart'; +import 'package:acela/src/screens/login/ha_login_screen.dart'; +import 'package:acela/src/screens/my_account/my_account_screen.dart'; +import 'package:acela/src/screens/podcast/view/podcast_trending.dart'; +import 'package:acela/src/screens/search/search_screen.dart'; +import 'package:acela/src/screens/stories/new_tab_based_stories.dart'; +import 'package:acela/src/screens/upload/podcast/podcast_upload_screen.dart'; +import 'package:acela/src/screens/upload/video/controller/video_upload_controller.dart'; +import 'package:acela/src/screens/upload/video/video_upload_screen.dart'; +import 'package:acela/src/widgets/custom_circle_avatar.dart'; +import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class BottomNavBar extends StatefulWidget { + const BottomNavBar({required this.appData, this.username}); + + final HiveUserData appData; + final String? username; + + @override + State createState() => _BottomNavBarState(); +} + +class _BottomNavBarState extends State { + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return SizedBox( + height: 65, + child: BottomNavigationBar( + showUnselectedLabels: true, + selectedFontSize: 11, + unselectedFontSize: 11, + type: BottomNavigationBarType.fixed, + items: [ + BottomNavigationBarItem( + icon: SizedBox(height: 25, child: Icon(Icons.search)), + label: 'Search', + ), + BottomNavigationBarItem( + icon: SizedBox( + height: 25, + child: Padding( + padding: const EdgeInsets.only(bottom: 0.0), + child: Image.asset( + 'assets/branding/three_shorts_icon.png', + height: 23, + width: 23, + ), + ), + ), + label: '3Shorts', + ), + BottomNavigationBarItem( + icon: SizedBox(height: 25, child: Icon(Icons.add)), + label: 'Upload', + ), + BottomNavigationBarItem( + icon: SizedBox( + height: 25, + child: Image.asset( + 'assets/pod-cast-logo-round.png', + height: 23, + width: 23, + ), + ), + label: 'Podcast', + ), + BottomNavigationBarItem( + icon: SizedBox( + height: 25, + child: widget.username == null + ? Icon(Icons.person) + : CustomCircleAvatar( + height: 23, + width: 23, + url: + 'https://images.hive.blog/u/${widget.username ?? ''}/avatar', + )), + label: 'You', + ), + ], + onTap: (index) => navigate(index, context), + selectedItemColor: theme.primaryColorLight, + unselectedItemColor: theme.primaryColorLight, + backgroundColor: theme.primaryColorDark, + ), + ); + } + + void navigate(int index, BuildContext context) { + switch (index) { + case 0: + _onTapSearch(); + break; + case 1: + _onTapThreeShorts(); + break; + case 2: + _uploadBottomSheet(); + break; + case 3: + _onTapPodcast(); + break; + case 4: + _onAccountTap(); + break; + } + } + + void _onTapThreeShorts() { + var screen = GQLStoriesScreen(appData: widget.appData); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + } + + Widget addPostButton(HiveUserData? userData) { + return Visibility( + visible: widget.username != null, + child: SizedBox( + width: 40, + child: IconButton( + color: Theme.of(context).primaryColorLight, + onPressed: () { + _uploadBottomSheet(); + }, + icon: Icon(Icons.add_circle), + )), + ); + } + + void _onTapPodcast() { + var screen = PodCastTrendingScreen(appData: widget.appData); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + } + + void _onTapSearch() { + var route = MaterialPageRoute( + builder: (context) => const SearchScreen(), + ); + Navigator.of(context).push(route); + } + + void _onAccountTap() { + if (widget.username == null) { + _loginBottomSheet(); + return; + } else { + var screen = MyAccountScreen(data: widget.appData); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + } + } + + void _loginBottomSheet() { + showAdaptiveActionSheet( + context: context, + title: const Text('You are not logged in. Please log in to upvote.'), + androidBorderRadius: 30, + actions: [ + BottomSheetAction( + title: Text('Log in'), + leading: Icon(Icons.login), + onPressed: (c) { + Navigator.of(c).pop(); + var screen = HiveAuthLoginScreen(appData: widget.appData); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(c).push(route); + }), + ], + cancelAction: CancelAction(title: const Text('Cancel')), + ); + } + + void _uploadBottomSheet() { + if (widget.username == null) { + _loginBottomSheet(); + } else { + showAdaptiveActionSheet( + context: context, + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.upload), + const SizedBox( + width: 5, + ), + const Text( + 'Upload', + style: TextStyle(fontSize: 20), + ), + ], + ), + androidBorderRadius: 30, + actions: [ + BottomSheetAction( + title: const Text('Video'), + leading: const Icon(Icons.video_call), + onPressed: (c) { + Navigator.pop(context); + if (!context.read().isFreshUpload()) { + var screen = VideoUploadScreen( + isCamera: true, + appData: widget.appData, + ); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + } else { + VideoUploadSheet.show(widget.appData, context); + } + }, + ), + BottomSheetAction( + title: const Text('Podcast'), + leading: const Icon(Icons.podcasts), + onPressed: (c) { + var route = MaterialPageRoute( + builder: (c) => PodcastUploadScreen(data: widget.appData)); + Navigator.of(context).pop(); + Navigator.of(context).push(route); + }), + ], + cancelAction: CancelAction( + title: const Text('Cancel'), + ), + ); + } + } +} diff --git a/lib/src/screens/home_screen/new_home_screen.dart b/lib/src/screens/home_screen/new_home_screen.dart index db2954ad..812974b1 100644 --- a/lib/src/screens/home_screen/new_home_screen.dart +++ b/lib/src/screens/home_screen/new_home_screen.dart @@ -1,23 +1,17 @@ - import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/about/about_home_screen.dart'; import 'package:acela/src/screens/communities_screen/communities_screen.dart'; -import 'package:acela/src/screens/favourites/user_favourites.dart'; +import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/tab_title_toast.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_list.dart'; import 'package:acela/src/screens/home_screen/video_upload_sheet.dart'; -import 'package:acela/src/screens/login/ha_login_screen.dart'; -import 'package:acela/src/screens/my_account/my_account_screen.dart'; import 'package:acela/src/screens/podcast/view/podcast_trending.dart'; import 'package:acela/src/screens/search/search_screen.dart'; -import 'package:acela/src/screens/settings/settings_screen.dart'; import 'package:acela/src/screens/stories/new_tab_based_stories.dart'; import 'package:acela/src/screens/trending_tags/trending_tags.dart'; import 'package:acela/src/screens/upload/podcast/podcast_upload_screen.dart'; import 'package:acela/src/screens/upload/video/controller/video_upload_controller.dart'; import 'package:acela/src/screens/upload/video/video_upload_screen.dart'; -import 'package:acela/src/widgets/fab_custom.dart'; -import 'package:acela/src/widgets/fab_overlay.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -38,7 +32,7 @@ class GQLFeedScreen extends StatefulWidget { } class _GQLFeedScreenState extends State - with SingleTickerProviderStateMixin { + with TickerProviderStateMixin { var isMenuOpen = false; List myTabs() { @@ -70,11 +64,16 @@ class _GQLFeedScreenState extends State super.initState(); _tabController = TabController(vsync: this, length: widget.username != null ? 6 : 5); - _tabController.addListener(() { - setState(() { - currentIndex = _tabController.index; - }); - }); + } + + @override + void didUpdateWidget(covariant GQLFeedScreen oldWidget) { + if (widget.username != oldWidget.username) { + _tabController.dispose(); + _tabController = + TabController(vsync: this, length: widget.username != null ? 6 : 5); + } + super.didUpdateWidget(oldWidget); } @override @@ -218,66 +217,83 @@ class _GQLFeedScreenState extends State showReleaseNotes: true, ), child: Scaffold( + bottomNavigationBar: BottomNavBar( + appData: widget.appData, + username: widget.username, + ), appBar: AppBar( title: appBarHeader(), bottom: TabBar( controller: _tabController, + onTap: (value) { + setState(() { + currentIndex = value; + }); + }, tabs: myTabs(), ), - actions: [ - searchIconButton(), - threeShortsActionButton(), - podcastsActionButton(), - addPostButton(widget.appData) - ], ), body: SafeArea( child: Stack( children: [ TabBarView( + key: ValueKey('${widget.username}'), controller: _tabController, children: widget.username != null ? [ HomeScreenFeedList( + key: ValueKey("${widget.username} 0"), showVideo: currentIndex == 0, feedType: HomeScreenFeedType.userFeed, appData: appData), HomeScreenFeedList( + key: ValueKey("${widget.username} 1"), showVideo: currentIndex == 1, feedType: HomeScreenFeedType.trendingFeed, appData: appData), HomeScreenFeedList( + key: ValueKey("${widget.username} 2"), showVideo: currentIndex == 2, feedType: HomeScreenFeedType.newUploads, appData: appData), HomeScreenFeedList( + key: ValueKey("${widget.username} 3"), showVideo: currentIndex == 3, feedType: HomeScreenFeedType.firstUploads, appData: appData), CommunitiesScreen( + key: ValueKey("${widget.username} 4"), didSelectCommunity: null, withoutScaffold: true, ), - TrendingTagsWidget(), + TrendingTagsWidget( + key: ValueKey("${widget.username} 5"), + ), ] : [ HomeScreenFeedList( + key: ValueKey("${widget.username} 0"), showVideo: currentIndex == 0, feedType: HomeScreenFeedType.trendingFeed, appData: appData), HomeScreenFeedList( + key: ValueKey("${widget.username} 1"), showVideo: currentIndex == 1, feedType: HomeScreenFeedType.newUploads, appData: appData), HomeScreenFeedList( + key: ValueKey("${widget.username} 2"), showVideo: currentIndex == 2, feedType: HomeScreenFeedType.firstUploads, appData: appData), CommunitiesScreen( + key: ValueKey("${widget.username} 3"), didSelectCommunity: null, withoutScaffold: true, ), - TrendingTagsWidget(), + TrendingTagsWidget( + key: ValueKey("${widget.username} 4"), + ), ]), Padding( padding: const EdgeInsets.only(top: 15.0), @@ -289,7 +305,6 @@ class _GQLFeedScreenState extends State ), ), ), - _fabContainer() ], ), ), @@ -297,127 +312,6 @@ class _GQLFeedScreenState extends State ); } - List _fabItems() { - List fabItems = []; - if (widget.username != null) { - fabItems.add(FabOverItemData( - displayName: 'Upload', - icon: Icons.upload, - onTap: () { - setState(() { - isMenuOpen = false; - uploadBottomSheet(widget.appData); - }); - }, - )); - fabItems.add( - FabOverItemData( - displayName: 'My Account', - icon: Icons.person, - url: 'https://images.hive.blog/u/${widget.username ?? ''}/avatar', - onTap: () { - setState(() { - isMenuOpen = false; - var screen = MyAccountScreen(data: widget.appData); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }); - }, - ), - ); - } else { - fabItems.add( - FabOverItemData( - displayName: 'Log in', - icon: Icons.person, - onTap: () { - setState(() { - isMenuOpen = false; - var screen = HiveAuthLoginScreen(appData: widget.appData); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }); - }, - ), - ); - } - fabItems.add( - FabOverItemData( - displayName: 'Bookmarks', - icon: Icons.bookmarks, - onTap: () { - setState(() { - isMenuOpen = false; - var screen = const UserFavourites(); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }); - }, - ), - ); - fabItems.add( - FabOverItemData( - displayName: 'Settings', - icon: Icons.settings, - onTap: () { - setState(() { - isMenuOpen = false; - var screen = const SettingsScreen(); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }); - }, - ), - ); - fabItems.add( - FabOverItemData( - displayName: 'Important 3Speak Links', - icon: Icons.link, - onTap: () { - setState(() { - isMenuOpen = false; - var screen = const AboutHomeScreen(); - var route = MaterialPageRoute(builder: (_) => screen); - Navigator.of(context).push(route); - }); - }, - ), - ); - fabItems.add( - FabOverItemData( - displayName: 'Close', - icon: Icons.close, - onTap: () { - setState(() { - isMenuOpen = false; - }); - }, - ), - ); - return fabItems; - } - - Widget _fabContainer() { - if (!isMenuOpen) { - return FabCustom( - icon: Icons.bolt, - onTap: () { - setState(() { - isMenuOpen = true; - }); - }, - ); - } - return FabOverlay( - items: _fabItems(), - onBackgroundTap: () { - setState(() { - isMenuOpen = false; - }); - }, - ); - } - void showError(String string) { var snackBar = SnackBar(content: Text('Error: $string')); ScaffoldMessenger.of(context).showSnackBar(snackBar); diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index a0c16465..44bae171 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -369,12 +369,6 @@ class _HiveAuthLoginScreenState extends State var cookie = await Communicator().getValidCookie(data); log(cookie); Navigator.of(context).pop(); - var screen = GQLFeedScreen( - appData: data, - username: usernameController.text, - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).pushReplacement(route); showMessage( 'You have successfully logged in as - ${usernameController.text}'); setState(() { @@ -468,12 +462,6 @@ class _HiveAuthLoginScreenState extends State showMessage( 'You have successfully logged in with Hive Auth with user - ${usernameController.text}'); Navigator.of(context).pop(); - var screen = GQLFeedScreen( - appData: newData, - username: usernameController.text, - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).pushReplacement(route); } } else { showMessage( diff --git a/lib/src/screens/my_account/account_settings/account_settings_screen.dart b/lib/src/screens/my_account/account_settings/account_settings_screen.dart index 0f7ba076..75b2dddb 100644 --- a/lib/src/screens/my_account/account_settings/account_settings_screen.dart +++ b/lib/src/screens/my_account/account_settings/account_settings_screen.dart @@ -48,12 +48,6 @@ class _AccountSettingsScreenState extends State { server.updateHiveUserData(newUserData); Navigator.of(context).pop(); Navigator.of(context).pop(); - Navigator.of(context).pushReplacement( - MaterialPageRoute( - builder: (context) => - GQLFeedScreen(appData: newUserData, username: null), - ), - ); } @override diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index 1c3405d3..fb18e517 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -2,11 +2,11 @@ import 'dart:developer'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; +import 'package:acela/src/screens/favourites/user_favourites.dart'; import 'package:acela/src/screens/my_account/update_thumb/update_thumb_screen.dart'; import 'package:acela/src/screens/my_account/update_video/video_primary_info.dart'; import 'package:acela/src/screens/my_account/video_preview.dart'; import 'package:acela/src/screens/settings/settings_screen.dart'; -import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/communicator.dart'; @@ -66,7 +66,8 @@ class _MyAccountScreenState extends State splashColor: Colors.transparent, contentPadding: EdgeInsets.zero, onTap: () { - context.pushNamed(Routes.userView, pathParameters: {'author': username}); + context + .pushNamed(Routes.userView, pathParameters: {'author': username}); }, leading: CustomCircleAvatar( height: 36, @@ -97,8 +98,18 @@ class _MyAccountScreenState extends State icon: Icon(Icons.refresh), ), IconButton( + icon: Icon(Icons.bookmarks), onPressed: () { - var screen = const SettingsScreen(isUserFromUserSettings: true,); + var screen = const UserFavourites(); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + ), + IconButton( + onPressed: () { + var screen = const SettingsScreen( + isUserFromUserSettings: true, + ); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); }, diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index 1726782b..469f029a 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -279,12 +279,6 @@ class _SettingsScreenState extends State { Navigator.of(context).pop(); } Navigator.of(context).pop(); - Navigator.of(context).pushReplacement( - MaterialPageRoute( - builder: (context) => - GQLFeedScreen(appData: newUserData, username: null), - ), - ); } Widget _deleteAccount() { diff --git a/lib/src/screens/upload/video/widgets/work_type_widget.dart b/lib/src/screens/upload/video/widgets/work_type_widget.dart index e426e726..95389930 100644 --- a/lib/src/screens/upload/video/widgets/work_type_widget.dart +++ b/lib/src/screens/upload/video/widgets/work_type_widget.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; class WorkTypeWidget extends StatefulWidget { const WorkTypeWidget( @@ -24,20 +25,23 @@ class _WorkTypeWidgetState extends State { @override Widget build(BuildContext context) { return Row( + mainAxisAlignment: MainAxisAlignment.start, children: [ - Text(isNsfwContent - ? 'Video is NOT SAFE for work.' - : 'Video is Safe for work.'), - const Spacer(), - Switch( - value: isNsfwContent, - onChanged: (newValue) { + Checkbox( + visualDensity: VisualDensity.compact, + value: isNsfwContent, onChanged: (newValue) { setState(() { - isNsfwContent = newValue; + isNsfwContent = newValue!; }); - widget.onChanged(newValue); - }, - ) + widget.onChanged(newValue!); + },), + Expanded( + child: Text( + "You should check this option if your content is NSFW", + style: TextStyle(color: Colors.red), + ), + ), + ], ); } diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index e33ec1ed..47ab474e 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -382,6 +382,7 @@ class Communicator { }) async { var request = http.Request( 'POST', Uri.parse('${Communicator.tsServer}/mobile/api/update_info')); + var cookie = await getValidCookie(user); request.body = VideoUploadCompleteRequest( videoId: videoId, title: title, @@ -392,7 +393,7 @@ class Communicator { communityID: communityID, ).toJsonString(); Map map = { - "cookie": user.cookie ?? "", + "cookie": cookie, "Content-Type": "application/json" }; request.headers.addAll(map); @@ -713,6 +714,7 @@ class Communicator { rethrow; } } + Future login( String userName, String proofOfPayload, From 914b11524fa644ddb4f0bf9708d9f082b640bb0d Mon Sep 17 00:00:00 2001 From: sagar Date: Thu, 14 Mar 2024 18:15:33 +0530 Subject: [PATCH 384/466] unwanted code remove --- .../screens/home_screen/new_home_screen.dart | 70 ------------------- 1 file changed, 70 deletions(-) diff --git a/lib/src/screens/home_screen/new_home_screen.dart b/lib/src/screens/home_screen/new_home_screen.dart index 812974b1..fb311592 100644 --- a/lib/src/screens/home_screen/new_home_screen.dart +++ b/lib/src/screens/home_screen/new_home_screen.dart @@ -4,15 +4,10 @@ import 'package:acela/src/screens/communities_screen/communities_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/tab_title_toast.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_list.dart'; -import 'package:acela/src/screens/home_screen/video_upload_sheet.dart'; import 'package:acela/src/screens/podcast/view/podcast_trending.dart'; import 'package:acela/src/screens/search/search_screen.dart'; import 'package:acela/src/screens/stories/new_tab_based_stories.dart'; import 'package:acela/src/screens/trending_tags/trending_tags.dart'; -import 'package:acela/src/screens/upload/podcast/podcast_upload_screen.dart'; -import 'package:acela/src/screens/upload/video/controller/video_upload_controller.dart'; -import 'package:acela/src/screens/upload/video/video_upload_screen.dart'; -import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:upgrader/upgrader.dart'; @@ -159,21 +154,6 @@ class _GQLFeedScreenState extends State ); } - Widget addPostButton(HiveUserData? userData) { - return Visibility( - visible: widget.username != null, - child: SizedBox( - width: 40, - child: IconButton( - color: Theme.of(context).primaryColorLight, - onPressed: () { - uploadBottomSheet(userData!); - }, - icon: Icon(Icons.add_circle), - )), - ); - } - SizedBox podcastsActionButton() { return SizedBox( width: 35, @@ -317,54 +297,4 @@ class _GQLFeedScreenState extends State ScaffoldMessenger.of(context).showSnackBar(snackBar); } - void uploadBottomSheet(HiveUserData data) { - showAdaptiveActionSheet( - context: context, - title: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.upload), - const SizedBox( - width: 5, - ), - const Text( - 'Upload', - style: TextStyle(fontSize: 20), - ), - ], - ), - androidBorderRadius: 30, - actions: [ - BottomSheetAction( - title: const Text('Video'), - leading: const Icon(Icons.video_call), - onPressed: (c) { - Navigator.pop(context); - if (!context.read().isFreshUpload()) { - var screen = VideoUploadScreen( - isCamera: true, - appData: data, - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - } else { - VideoUploadSheet.show(data, context); - } - }, - ), - BottomSheetAction( - title: const Text('Podcast'), - leading: const Icon(Icons.podcasts), - onPressed: (c) { - var route = MaterialPageRoute( - builder: (c) => PodcastUploadScreen(data: widget.appData)); - Navigator.of(context).pop(); - Navigator.of(context).push(route); - }), - ], - cancelAction: CancelAction( - title: const Text('Cancel'), - ), - ); - } } From 1ec1e3679cd1d2e3e97b073d1b693c02c8e14578 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 14 Mar 2024 21:50:03 +0530 Subject: [PATCH 385/466] 2.5.0 (91) appstore & playStore release --- .idea/Android-App.iml | 6 ++ ios/Runner.xcodeproj/project.pbxproj | 14 ++--- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- .../widgets/bottom_nav_bar.dart | 2 +- lib/src/screens/login/ha_login_screen.dart | 2 +- pubspec.lock | 56 +++++++++++++++---- pubspec.yaml | 2 +- 7 files changed, 61 insertions(+), 23 deletions(-) diff --git a/.idea/Android-App.iml b/.idea/Android-App.iml index 3716c8a4..1699252d 100644 --- a/.idea/Android-App.iml +++ b/.idea/Android-App.iml @@ -182,6 +182,12 @@ + + + + + + diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 7f1a4f8b..98142e8b 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -220,7 +220,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -460,10 +460,10 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = "${FLUTTER_BUILD_NUMBER}"; + CURRENT_PROJECT_VERSION = 91; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; - FLUTTER_BUILD_NUMBER = 90; + FLUTTER_BUILD_NUMBER = 91; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = 3Speak.tv; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.video"; @@ -606,10 +606,10 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = "${FLUTTER_BUILD_NUMBER}"; + CURRENT_PROJECT_VERSION = 91; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; - FLUTTER_BUILD_NUMBER = 90; + FLUTTER_BUILD_NUMBER = 91; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = 3Speak.tv; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.video"; @@ -638,10 +638,10 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = "${FLUTTER_BUILD_NUMBER}"; + CURRENT_PROJECT_VERSION = 91; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; - FLUTTER_BUILD_NUMBER = 90; + FLUTTER_BUILD_NUMBER = 91; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = 3Speak.tv; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.video"; diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826db..5e31d3d3 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ { void _loginBottomSheet() { showAdaptiveActionSheet( context: context, - title: const Text('You are not logged in. Please log in to upvote.'), + title: const Text('You are not logged in. Please log in.'), androidBorderRadius: 30, actions: [ BottomSheetAction( diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index 44bae171..de406e79 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -221,7 +221,7 @@ class _HiveAuthLoginScreenState extends State const SizedBox(height: 10), Image.asset('assets/hive_auth_button.png'), const SizedBox(height: 10), - Text('Scan QR Code'), + Text('Scan QR Code\n- OR - \nTap on QR Code'), SizedBox(height: 10), InkWell( child: Container( diff --git a/pubspec.lock b/pubspec.lock index 0acdf5f4..e84b9dfe 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -954,6 +954,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.9" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + url: "https://pub.dev" + source: hosted + version: "10.0.4" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: @@ -990,26 +1014,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.0" mime: dependency: transitive description: @@ -1078,10 +1102,10 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: "direct main" description: @@ -1467,10 +1491,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.0" timeago: dependency: "direct main" description: @@ -1679,6 +1703,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.3" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: a2662fb1f114f4296cf3f5a50786a2d888268d7776cf681aa17d660ffa23b246 + url: "https://pub.dev" + source: hosted + version: "14.0.0" wakelock: dependency: "direct main" description: @@ -1808,5 +1840,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.3 <4.0.0" - flutter: ">=3.16.6" + dart: ">=3.3.0-0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/pubspec.yaml b/pubspec.yaml index 977cee47..2d5f630e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.4.1+90 +version: 2.5.0+91 environment: sdk: ">=2.15.1 <3.0.0" From 5f68917cebcebad1b2a905e52283771b3f102d9e Mon Sep 17 00:00:00 2001 From: sagar Date: Mon, 25 Mar 2024 13:02:43 +0530 Subject: [PATCH 386/466] nav bar items change on login/logout, user bookmark,log out location change and more --- .../favourites/favourite_shorts_body.dart | 2 +- .../favourites/favourite_tags_body.dart | 2 +- .../favourites/favourite_users_body.dart | 45 +++++ .../favourites/favourite_video_body.dart | 2 +- .../screens/favourites/user_favourites.dart | 11 +- .../widgets/bottom_nav_bar.dart | 166 +++++++++++------- .../home_screen/home_screen_feed_list.dart | 32 ++-- .../screens/home_screen/new_home_screen.dart | 93 ++++------ .../screens/my_account/my_account_screen.dart | 126 +++++++++---- .../screens/podcast/widgets/favourite.dart | 4 +- lib/src/screens/settings/settings_screen.dart | 16 -- .../user_channel_screen.dart | 12 ++ .../user_favourite_provider.dart | 47 +++++ lib/src/widgets/custom_circle_avatar.dart | 5 +- 14 files changed, 370 insertions(+), 193 deletions(-) create mode 100644 lib/src/screens/favourites/favourite_users_body.dart create mode 100644 lib/src/screens/user_channel_screen/user_favourite_provider.dart diff --git a/lib/src/screens/favourites/favourite_shorts_body.dart b/lib/src/screens/favourites/favourite_shorts_body.dart index 5e44a6a3..0e45040d 100644 --- a/lib/src/screens/favourites/favourite_shorts_body.dart +++ b/lib/src/screens/favourites/favourite_shorts_body.dart @@ -32,7 +32,7 @@ class _FavouriteShortsBodyState extends State { appData: widget.appData, controller: controller) : Center( - child: Text("No favourite shorts found"), + child: Text("No Bookmarked shorts found"), ); } } diff --git a/lib/src/screens/favourites/favourite_tags_body.dart b/lib/src/screens/favourites/favourite_tags_body.dart index 08753be2..2d2d71c0 100644 --- a/lib/src/screens/favourites/favourite_tags_body.dart +++ b/lib/src/screens/favourites/favourite_tags_body.dart @@ -32,7 +32,7 @@ class FavouriteTagsBody extends StatelessWidget { }, ) : const Center( - child: Text("No favourite tags found"), + child: Text("No Bookmarked tags found"), ); } } diff --git a/lib/src/screens/favourites/favourite_users_body.dart b/lib/src/screens/favourites/favourite_users_body.dart new file mode 100644 index 00000000..2659c9a4 --- /dev/null +++ b/lib/src/screens/favourites/favourite_users_body.dart @@ -0,0 +1,45 @@ +import 'package:acela/src/bloc/server.dart'; +import 'package:acela/src/screens/user_channel_screen/user_channel_screen.dart'; +import 'package:acela/src/screens/user_channel_screen/user_favourite_provider.dart'; +import 'package:acela/src/widgets/custom_circle_avatar.dart'; +import 'package:flutter/material.dart'; + +class FavouriteUsersBody extends StatelessWidget { + const FavouriteUsersBody({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final UserFavoriteProvider dataProvider = UserFavoriteProvider(); + List items = dataProvider.getBookmarkedUsers(); + return items.isNotEmpty + ? ListView.builder( + itemCount: items.length, + itemBuilder: (context, index) { + String user = items[index]; + return Dismissible( + key: Key(user), + background: Center(child: Text("Delete")), + onDismissed: (direction) { + dataProvider.storeLikedUserLocally(user, forceRemove: true); + }, + child: ListTile( + onTap: () { + var screen = UserChannelScreen(owner: user); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + leading: CustomCircleAvatar( + height: 36, + width: 36, + url: server.userOwnerThumb(user), + ), + title: Text(user), + ), + ); + }, + ) + : const Center( + child: Text("No Bookmarked users found"), + ); + } +} diff --git a/lib/src/screens/favourites/favourite_video_body.dart b/lib/src/screens/favourites/favourite_video_body.dart index 96181e6b..f12e4875 100644 --- a/lib/src/screens/favourites/favourite_video_body.dart +++ b/lib/src/screens/favourites/favourite_video_body.dart @@ -45,7 +45,7 @@ class _FavouriteVideoBodyState extends State { itemCount: items.length % 50 == 0 ? items.length + 1 : items.length, ) : Center( - child: Text("No favourite vidoes found"), + child: Text("No Bookmarked vidoes found"), ); } } diff --git a/lib/src/screens/favourites/user_favourites.dart b/lib/src/screens/favourites/user_favourites.dart index 9c67e8db..9ea3c7bb 100644 --- a/lib/src/screens/favourites/user_favourites.dart +++ b/lib/src/screens/favourites/user_favourites.dart @@ -1,6 +1,7 @@ import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/favourites/favourite_shorts_body.dart'; import 'package:acela/src/screens/favourites/favourite_tags_body.dart'; +import 'package:acela/src/screens/favourites/favourite_users_body.dart'; import 'package:acela/src/screens/favourites/favourite_video_body.dart'; import 'package:acela/src/screens/podcast/view/liked_podcasts.dart'; import 'package:acela/src/screens/podcast/view/local_podcast_episode.dart'; @@ -24,7 +25,7 @@ class _UserFavouritesState extends State @override void initState() { super.initState(); - _tabController = TabController(length: 6, vsync: this); + _tabController = TabController(length: 7, vsync: this); _tabController.addListener(() { setState(() { currentIndex = _tabController.index; @@ -53,6 +54,7 @@ class _UserFavouritesState extends State Tab(icon: const Icon(Icons.play_arrow)), Tab(icon: const Icon(Icons.video_library_rounded)), Tab(icon: const Icon(Icons.tag)), + Tab(icon: const Icon(Icons.person)), Tab(icon: const Icon(Icons.podcasts)), Tab(icon: const Icon(Icons.queue_music_rounded)), Tab(icon: const Icon(FontAwesomeIcons.download)), @@ -65,6 +67,7 @@ class _UserFavouritesState extends State appData: appData, ), FavouriteTagsBody(), + FavouriteUsersBody(), LikedPodcasts( appData: appData, showAppBar: false, @@ -84,10 +87,12 @@ class _UserFavouritesState extends State case 2: return "Tags"; case 3: - return "Podcasts"; + return "Users"; case 4: - return "Podcast Episode"; + return "Podcasts"; case 5: + return "Podcast Episode"; + case 6: return "Offline Podcast Episode"; default: return ""; diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart index 457fb4ab..7b68097f 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart @@ -34,54 +34,7 @@ class _BottomNavBarState extends State { selectedFontSize: 11, unselectedFontSize: 11, type: BottomNavigationBarType.fixed, - items: [ - BottomNavigationBarItem( - icon: SizedBox(height: 25, child: Icon(Icons.search)), - label: 'Search', - ), - BottomNavigationBarItem( - icon: SizedBox( - height: 25, - child: Padding( - padding: const EdgeInsets.only(bottom: 0.0), - child: Image.asset( - 'assets/branding/three_shorts_icon.png', - height: 23, - width: 23, - ), - ), - ), - label: '3Shorts', - ), - BottomNavigationBarItem( - icon: SizedBox(height: 25, child: Icon(Icons.add)), - label: 'Upload', - ), - BottomNavigationBarItem( - icon: SizedBox( - height: 25, - child: Image.asset( - 'assets/pod-cast-logo-round.png', - height: 23, - width: 23, - ), - ), - label: 'Podcast', - ), - BottomNavigationBarItem( - icon: SizedBox( - height: 25, - child: widget.username == null - ? Icon(Icons.person) - : CustomCircleAvatar( - height: 23, - width: 23, - url: - 'https://images.hive.blog/u/${widget.username ?? ''}/avatar', - )), - label: 'You', - ), - ], + items: navItems, onTap: (index) => navigate(index, context), selectedItemColor: theme.primaryColorLight, unselectedItemColor: theme.primaryColorLight, @@ -90,23 +43,108 @@ class _BottomNavBarState extends State { ); } + List get navItems { + List items = []; + items.add( + BottomNavigationBarItem( + icon: SizedBox(height: 25, child: Icon(Icons.search)), + label: 'Search', + ), + ); + + items.add( + BottomNavigationBarItem( + icon: SizedBox( + height: 25, + child: Padding( + padding: const EdgeInsets.only(bottom: 0.0), + child: Image.asset( + 'assets/branding/three_shorts_icon.png', + height: 23, + width: 23, + ), + ), + ), + label: '3Shorts', + ), + ); + + if (widget.username != null) { + items.add( + BottomNavigationBarItem( + icon: SizedBox(height: 25, child: Icon(Icons.add)), + label: 'Upload', + ), + ); + } + + items.add( + BottomNavigationBarItem( + icon: SizedBox( + height: 25, + child: Image.asset( + 'assets/pod-cast-logo-round.png', + height: 23, + width: 23, + ), + ), + label: 'Podcast', + ), + ); + if (widget.username != null) { + items.add( + BottomNavigationBarItem( + icon: SizedBox( + height: 25, + child: widget.username == null + ? Icon(Icons.person) + : CustomCircleAvatar( + height: 23, + width: 23, + color: Theme.of(context).primaryColorLight == Colors.black + ? Colors.grey.shade400 + : Colors.grey.shade900, + url: + 'https://images.hive.blog/u/${widget.username ?? ''}/avatar', + )), + label: 'You', + ), + ); + } + return items; + } + void navigate(int index, BuildContext context) { - switch (index) { - case 0: - _onTapSearch(); - break; - case 1: - _onTapThreeShorts(); - break; - case 2: - _uploadBottomSheet(); - break; - case 3: - _onTapPodcast(); - break; - case 4: - _onAccountTap(); - break; + if (widget.username != null) { + switch (index) { + case 0: + _onTapSearch(); + break; + case 1: + _onTapThreeShorts(); + break; + case 2: + _uploadBottomSheet(); + break; + case 3: + _onTapPodcast(); + break; + case 4: + _onAccountTap(); + break; + } + } else { + switch (index) { + case 0: + _onTapSearch(); + break; + case 1: + _onTapThreeShorts(); + break; + case 2: + _onTapPodcast(); + break; + } } } diff --git a/lib/src/screens/home_screen/home_screen_feed_list.dart b/lib/src/screens/home_screen/home_screen_feed_list.dart index f4d1ea07..2a00ce84 100644 --- a/lib/src/screens/home_screen/home_screen_feed_list.dart +++ b/lib/src/screens/home_screen/home_screen_feed_list.dart @@ -25,20 +25,21 @@ enum HomeScreenFeedType { } class HomeScreenFeedList extends StatefulWidget { - const HomeScreenFeedList({ - Key? key, - required this.appData, - required this.feedType, - this.owner, - this.community, - this.showVideo = true, - }); + const HomeScreenFeedList( + {Key? key, + required this.appData, + required this.feedType, + this.owner, + this.community, + this.showVideo = true, + this.onEmptyDataCallback}); final HiveUserData appData; final HomeScreenFeedType feedType; final String? owner; final String? community; final bool showVideo; + final VoidCallback? onEmptyDataCallback; @override State createState() => _HomeScreenFeedListState(); @@ -161,6 +162,9 @@ class _HomeScreenFeedListState extends State isPageEnded = true; } items = newItems; + if (items.isEmpty && widget.onEmptyDataCallback != null) { + widget.onEmptyDataCallback!(); + } isLoading = false; firstPageLoaded = true; }); @@ -209,8 +213,16 @@ class _HomeScreenFeedListState extends State child: Column( children: [ Spacer(), - Text( - 'We did not find anything to show.\nTap on Reload button to try again.'), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: Text( + widget.feedType == HomeScreenFeedType.userFeed + ? 'Please follow more people to see videos they publish.' + : 'We did not find anything to show.\nTap on Reload button to try again.', + textAlign: TextAlign.center, + ), + ), + const SizedBox(height: 5,), ElevatedButton( onPressed: () { loadFeed(true); diff --git a/lib/src/screens/home_screen/new_home_screen.dart b/lib/src/screens/home_screen/new_home_screen.dart index fb311592..d322afde 100644 --- a/lib/src/screens/home_screen/new_home_screen.dart +++ b/lib/src/screens/home_screen/new_home_screen.dart @@ -4,6 +4,7 @@ import 'package:acela/src/screens/communities_screen/communities_screen.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/tab_title_toast.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_list.dart'; +import 'package:acela/src/screens/login/ha_login_screen.dart'; import 'package:acela/src/screens/podcast/view/podcast_trending.dart'; import 'package:acela/src/screens/search/search_screen.dart'; import 'package:acela/src/screens/stories/new_tab_based_stories.dart'; @@ -127,63 +128,6 @@ class _GQLFeedScreenState extends State }, ), title: Text('3Speak.tv'), - // subtitle: Text( - // getSubtitle(), - // maxLines: 1, - // overflow: TextOverflow.ellipsis, - // style: TextStyle(fontSize: 13), - // ), - ); - } - - SizedBox threeShortsActionButton() { - return SizedBox( - width: 35, - child: IconButton( - onPressed: () { - var screen = GQLStoriesScreen(appData: widget.appData); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - icon: Image.asset( - 'assets/branding/three_shorts_icon.png', - height: 25, - width: 25, - ), - ), - ); - } - - SizedBox podcastsActionButton() { - return SizedBox( - width: 35, - child: IconButton( - onPressed: () { - var screen = PodCastTrendingScreen(appData: widget.appData); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - icon: Image.asset( - 'assets/pod-cast-logo-round.png', - height: 25, - width: 25, - ), - ), - ); - } - - SizedBox searchIconButton() { - return SizedBox( - width: 40, - child: IconButton( - onPressed: () { - var route = MaterialPageRoute( - builder: (context) => const SearchScreen(), - ); - Navigator.of(context).push(route); - }, - icon: Icon(Icons.search), - ), ); } @@ -212,6 +156,28 @@ class _GQLFeedScreenState extends State }, tabs: myTabs(), ), + actions: [ + if (widget.username == null) + Padding( + padding: const EdgeInsets.only(right: 15.0), + child: SizedBox( + height: 25, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4))), + padding: + EdgeInsets.symmetric(horizontal: 2, vertical: 0)), + onPressed: () { + var screen = HiveAuthLoginScreen(appData: widget.appData); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + child: Text('Log In'), + ), + ), + ), + ], ), body: SafeArea( child: Stack( @@ -222,10 +188,14 @@ class _GQLFeedScreenState extends State children: widget.username != null ? [ HomeScreenFeedList( - key: ValueKey("${widget.username} 0"), - showVideo: currentIndex == 0, - feedType: HomeScreenFeedType.userFeed, - appData: appData), + key: ValueKey("${widget.username} 0"), + showVideo: currentIndex == 0, + feedType: HomeScreenFeedType.userFeed, + appData: appData, + onEmptyDataCallback: () { + _tabController.animateTo(1); + }, + ), HomeScreenFeedList( key: ValueKey("${widget.username} 1"), showVideo: currentIndex == 1, @@ -296,5 +266,4 @@ class _GQLFeedScreenState extends State var snackBar = SnackBar(content: Text('Error: $string')); ScaffoldMessenger.of(context).showSnackBar(snackBar); } - } diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index fb18e517..ddda55d1 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -1,5 +1,6 @@ import 'dart:developer'; +import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/screens/favourites/user_favourites.dart'; @@ -10,11 +11,13 @@ import 'package:acela/src/screens/settings/settings_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_screen.dart'; import 'package:acela/src/screens/video_details_screen/video_details_view_model.dart'; import 'package:acela/src/utils/communicator.dart'; +import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:acela/src/utils/routes/routes.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:go_router/go_router.dart'; class MyAccountScreen extends StatefulWidget { @@ -89,14 +92,6 @@ class _MyAccountScreenState extends State ], ), actions: [ - IconButton( - onPressed: () { - setState(() { - loadVideos = Communicator().loadVideos(widget.data); - }); - }, - icon: Icon(Icons.refresh), - ), IconButton( icon: Icon(Icons.bookmarks), onPressed: () { @@ -114,6 +109,35 @@ class _MyAccountScreenState extends State Navigator.of(context).push(route); }, icon: const Icon(Icons.settings), + ), + IconButton( + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('Log Out'), + content: Text('Are you sure you want to log out?'), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text('No'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + logout(widget.data); + }, + child: Text('Yes'), + ), + ], + ); + }, + ); + }, + icon: const Icon(Icons.logout_outlined), ) ], ); @@ -306,31 +330,38 @@ class _MyAccountScreenState extends State child: Text('No Items found.'), ); } - return ListView.separated( - itemBuilder: (context, index) { - if (index == 0) { - var text = currentIndex == 0 - ? 'Your videos are ready to post\nTap on a video to edit details & publish' - : currentIndex == 1 - ? 'Following videos are already posted\nTap on a video to change thumbnail' - : "Here you'll see list of videos which are either in video encoding process or deleted."; - return Padding( - padding: const EdgeInsets.only( - top: 15.0, left: 15, right: 15, bottom: 20), - child: Text( - text, - textAlign: TextAlign.center, - style: TextStyle(color: Theme.of(context).primaryColorLight), - ), - ); - } - return _videoListItem(items[index - 1], user); + return RefreshIndicator( + onRefresh: () async { + setState(() { + loadVideos = Communicator().loadVideos(widget.data); + }); }, - separatorBuilder: (context, index) => const Divider( - height: 0, - color: Colors.transparent, + child: ListView.separated( + itemBuilder: (context, index) { + if (index == 0) { + var text = currentIndex == 0 + ? 'Your videos are ready to post\nTap on a video to edit details & publish' + : currentIndex == 1 + ? 'Following videos are already posted\nTap on a video to change thumbnail' + : "Here you'll see list of videos which are either in video encoding process or deleted."; + return Padding( + padding: const EdgeInsets.only( + top: 15.0, left: 15, right: 15, bottom: 20), + child: Text( + text, + textAlign: TextAlign.center, + style: TextStyle(color: Theme.of(context).primaryColorLight), + ), + ); + } + return _videoListItem(items[index - 1], user); + }, + separatorBuilder: (context, index) => const Divider( + height: 0, + color: Colors.transparent, + ), + itemCount: items.length + 1, ), - itemCount: items.length + 1, ); } @@ -394,6 +425,39 @@ class _MyAccountScreenState extends State ); } + Future logout(HiveUserData data) async { + // Create storage + const storage = FlutterSecureStorage(); + await storage.delete(key: 'username'); + await storage.delete(key: 'postingKey'); + await storage.delete(key: 'accessToken'); + await storage.delete(key: 'postingAuth'); + await storage.delete(key: 'cookie'); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); + String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + String union = + await storage.read(key: 'union') ?? GQLCommunicator.defaultGQLServer; + String? lang = await storage.read(key: 'lang'); + var newUserData = HiveUserData( + username: null, + postingKey: null, + keychainData: null, + cookie: null, + accessToken: null, + postingAuthority: null, + resolution: resolution, + rpc: rpc, + union: union, + loaded: true, + language: lang, + ); + server.updateHiveUserData(newUserData); + Navigator.of(context).pop(); + } + @override Widget build(BuildContext context) { return DefaultTabController( diff --git a/lib/src/screens/podcast/widgets/favourite.dart b/lib/src/screens/podcast/widgets/favourite.dart index 965c600e..f638a5f4 100644 --- a/lib/src/screens/podcast/widgets/favourite.dart +++ b/lib/src/screens/podcast/widgets/favourite.dart @@ -71,8 +71,8 @@ class _FavouriteWidgetState extends State { void showSnackBar(bool isAdding) { final String message = isAdding - ? "is added to your favourites" - : "is removed from your favourites"; + ? "is added to your bookmarks" + : "is removed from your bookmarks"; ScaffoldMessenger.of(context).hideCurrentSnackBar(); ScaffoldMessenger.of(context).showSnackBar(SnackBar( backgroundColor: Colors.black, diff --git a/lib/src/screens/settings/settings_screen.dart b/lib/src/screens/settings/settings_screen.dart index 469f029a..acd9f532 100644 --- a/lib/src/screens/settings/settings_screen.dart +++ b/lib/src/screens/settings/settings_screen.dart @@ -231,20 +231,6 @@ class _SettingsScreenState extends State { ); } - Widget _logout() { - var data = context.read(); - return Visibility( - visible: data.username != null, - child: ListTile( - leading: const Icon(Icons.logout), - title: const Text('Log Out'), - onTap: () { - logout(data); - }, - ), - ); - } - Future logout(HiveUserData data) async { // Create storage const storage = FlutterSecureStorage(); @@ -678,8 +664,6 @@ class _SettingsScreenState extends State { _divider(), _appVersion(context), _divider(), - _logout(), - _divider(), _deleteAccount(), _divider() ], diff --git a/lib/src/screens/user_channel_screen/user_channel_screen.dart b/lib/src/screens/user_channel_screen/user_channel_screen.dart index f8147a3a..b7fb481a 100644 --- a/lib/src/screens/user_channel_screen/user_channel_screen.dart +++ b/lib/src/screens/user_channel_screen/user_channel_screen.dart @@ -1,10 +1,12 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_list.dart'; +import 'package:acela/src/screens/podcast/widgets/favourite.dart'; import 'package:acela/src/screens/stories/story_feed_list.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_following.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_profile.dart'; import 'package:acela/src/screens/user_channel_screen/user_channel_videos.dart'; +import 'package:acela/src/screens/user_channel_screen/user_favourite_provider.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; @@ -26,6 +28,7 @@ class _UserChannelScreenState extends State late TabController _tabController; var currentIndex = 0; var videoKey = GlobalKey(); + var userFavouriteProvider = UserFavoriteProvider(); static List tabs = [ Tab( @@ -123,6 +126,15 @@ class _UserChannelScreenState extends State ], ), actions: [ + FavouriteWidget( + toastType: "User", + isLiked: userFavouriteProvider.isUserPresentLocally(widget.owner), + onAdd: () { + userFavouriteProvider.storeLikedUserLocally(widget.owner); + }, + onRemove: () { + userFavouriteProvider.storeLikedUserLocally(widget.owner); + }), IconButton( onPressed: () async { Share.share("https://3speak.tv/rss/${widget.owner}.xml"); diff --git a/lib/src/screens/user_channel_screen/user_favourite_provider.dart b/lib/src/screens/user_channel_screen/user_favourite_provider.dart new file mode 100644 index 00000000..11053832 --- /dev/null +++ b/lib/src/screens/user_channel_screen/user_favourite_provider.dart @@ -0,0 +1,47 @@ +import 'package:get_storage/get_storage.dart'; + +class UserFavoriteProvider { + final box = GetStorage(); + final String _usersLocalKey = '_userLocalKey'; + + List getBookmarkedUsers() { + final String key = _usersLocalKey; + if (box.read(key) != null) { + List items = box.read(key); + return items; + } else { + return []; + } + } + + //check if the liked podcast single episode is present locally + bool isUserPresentLocally(String userName) { + final String key = _usersLocalKey; + if (box.read(key) != null) { + List json = box.read(key); + int index = json.indexWhere((element) => element == userName); + return index != -1; + } else { + return false; + } + } + + //sotre the single podcast episode locally if user likes it + void storeLikedUserLocally(String userName, {bool forceRemove = false}) { + final String key = _usersLocalKey; + if (box.read(key) != null) { + List json = box.read(key); + int index = json.indexWhere((element) => element == userName); + if (index == -1 && !forceRemove) { + json.add(userName); + box.write(key, json); + } else { + json.removeWhere((element) => element == userName); + box.write(key, json); + } + } else { + box.write(key, [userName]); + } + print(box.read(key)); + } +} diff --git a/lib/src/widgets/custom_circle_avatar.dart b/lib/src/widgets/custom_circle_avatar.dart index 52cff1e9..3238b4d3 100644 --- a/lib/src/widgets/custom_circle_avatar.dart +++ b/lib/src/widgets/custom_circle_avatar.dart @@ -2,11 +2,12 @@ import 'package:flutter/material.dart'; class CustomCircleAvatar extends StatelessWidget { const CustomCircleAvatar( - {Key? key, required this.height, required this.width, required this.url}) + {Key? key, required this.height, required this.width, required this.url,this.color}) : super(key: key); final double height; final double width; final String url; + final Color? color; @override Widget build(BuildContext context) { @@ -15,7 +16,7 @@ class CustomCircleAvatar extends StatelessWidget { width: width, child: CircleAvatar( backgroundImage: NetworkImage(url), - backgroundColor: Colors.transparent, + backgroundColor:color ?? Colors.transparent, radius: 100, ), ); From 6f69155abef75b5a1fd274a7483f159b269d9008 Mon Sep 17 00:00:00 2001 From: sagar Date: Mon, 25 Mar 2024 14:38:06 +0530 Subject: [PATCH 387/466] 3shorts improvements - tab order changed,posted date text,removed extra comment button, on upvote upvote button is highlighed --- .../models/hive_post_info/hive_post_info.dart | 22 ++++- .../stories/new_tab_based_stories.dart | 46 +++++----- lib/src/widgets/story_player.dart | 89 ++++++++----------- 3 files changed, 80 insertions(+), 77 deletions(-) diff --git a/lib/src/models/hive_post_info/hive_post_info.dart b/lib/src/models/hive_post_info/hive_post_info.dart index 4e7c9e92..456b1f59 100644 --- a/lib/src/models/hive_post_info/hive_post_info.dart +++ b/lib/src/models/hive_post_info/hive_post_info.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:acela/src/utils/safe_convert.dart'; +import 'package:equatable/equatable.dart'; class HivePostInfo { final String jsonrpc; @@ -49,6 +50,18 @@ class HivePostInfoPostResultBody { required this.permlink, }); + HivePostInfoPostResultBody copyWith({ + double? payout, + List? activeVotes, + String? permlink, + }) { + return HivePostInfoPostResultBody( + payout: payout ?? this.payout, + activeVotes: activeVotes ?? this.activeVotes, + permlink: permlink ?? this.permlink, + ); + } + factory HivePostInfoPostResultBody.fromJson(Map? json) => HivePostInfoPostResultBody( payout: asDouble(json, 'payout'), @@ -65,11 +78,11 @@ class HivePostInfoPostResultBody { }; } -class ActiveVotesItem { +class ActiveVotesItem extends Equatable { final int rshares; final String voter; - ActiveVotesItem({ + const ActiveVotesItem({ this.rshares = 0, this.voter = "", }); @@ -79,9 +92,12 @@ class ActiveVotesItem { rshares: asInt(json, 'rshares'), voter: asString(json, 'voter'), ); - + Map toJson() => { 'rshares': rshares, 'voter': voter, }; + + @override + List get props => [voter]; } diff --git a/lib/src/screens/stories/new_tab_based_stories.dart b/lib/src/screens/stories/new_tab_based_stories.dart index 13a6ad73..a59cac36 100644 --- a/lib/src/screens/stories/new_tab_based_stories.dart +++ b/lib/src/screens/stories/new_tab_based_stories.dart @@ -22,6 +22,11 @@ class _GQLStoriesScreenState extends State List myTabs() { return widget.appData.username != null ? [ + // Tab(icon: Icon(Icons.home)), + Tab(icon: Icon(Icons.local_fire_department)), + Tab(icon: Icon(Icons.play_arrow)), + Tab(icon: Icon(Icons.looks_one)), + Tab(icon: Icon(Icons.person)), Tab( icon: Image.asset( 'assets/ctt-logo.png', @@ -29,13 +34,11 @@ class _GQLStoriesScreenState extends State height: 30, ), ), - Tab(icon: Icon(Icons.person)), - // Tab(icon: Icon(Icons.home)), + ] + : [ Tab(icon: Icon(Icons.local_fire_department)), Tab(icon: Icon(Icons.play_arrow)), Tab(icon: Icon(Icons.looks_one)), - ] - : [ Tab( icon: Image.asset( 'assets/ctt-logo.png', @@ -43,9 +46,6 @@ class _GQLStoriesScreenState extends State height: 30, ), ), - Tab(icon: Icon(Icons.local_fire_department)), - Tab(icon: Icon(Icons.play_arrow)), - Tab(icon: Icon(Icons.looks_one)), ]; } @@ -74,28 +74,28 @@ class _GQLStoriesScreenState extends State if (widget.appData.username != null) { switch (currentIndex) { case 0: - return 'CTT Chat'; + return 'Trending feed'; case 1: - return '@${widget.appData.username ?? 'User'}\'s feed'; + return 'New feed'; case 2: - return 'Trending feed'; + return 'First uploads'; case 3: - return 'New feed'; + return '@${widget.appData.username ?? 'User'}\'s feed'; case 4: - return 'First uploads'; + return 'CTT Chat'; default: return 'User\'s feed'; } } else { switch (currentIndex) { case 0: - return 'CTT Chat'; - case 1: return 'Trending feed'; - case 2: + case 1: return 'New feed'; - case 3: + case 2: return 'First uploads'; + case 3: + return 'CTT Chat'; default: return 'User\'s feed'; } @@ -144,11 +144,6 @@ class _GQLStoriesScreenState extends State controller: _tabController, children: widget.appData.username != null ? [ - StoryFeedList( - appData: widget.appData, feedType: StoryFeedType.cttFeed), - StoryFeedList( - appData: widget.appData, - feedType: StoryFeedType.userFeed), StoryFeedList( appData: widget.appData, feedType: StoryFeedType.trendingFeed), @@ -158,10 +153,13 @@ class _GQLStoriesScreenState extends State StoryFeedList( appData: widget.appData, feedType: StoryFeedType.firstUploads), - ] - : [ + StoryFeedList( + appData: widget.appData, + feedType: StoryFeedType.userFeed), StoryFeedList( appData: widget.appData, feedType: StoryFeedType.cttFeed), + ] + : [ StoryFeedList( appData: widget.appData, feedType: StoryFeedType.trendingFeed), @@ -171,6 +169,8 @@ class _GQLStoriesScreenState extends State StoryFeedList( appData: widget.appData, feedType: StoryFeedType.firstUploads), + StoryFeedList( + appData: widget.appData, feedType: StoryFeedType.cttFeed), ], ), ), diff --git a/lib/src/widgets/story_player.dart b/lib/src/widgets/story_player.dart index eb4acd6f..7b2f3377 100644 --- a/lib/src/widgets/story_player.dart +++ b/lib/src/widgets/story_player.dart @@ -23,6 +23,7 @@ import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; import 'package:http/http.dart' as http; +import 'package:timeago/timeago.dart' as timeago; class StoryPlayer extends StatefulWidget { const StoryPlayer({ @@ -259,7 +260,12 @@ class _StoryPlayerState extends State { activeVotes: postInfo!.activeVotes, onClose: () {}, onDone: () { - loadHiveInfo(); + setState(() { + postInfo = postInfo!.copyWith(activeVotes: [ + ...postInfo!.activeVotes, + ActiveVotesItem(voter: widget.data.username!) + ]); + }); }, ), ); @@ -267,44 +273,6 @@ class _StoryPlayerState extends State { ); } - void commentPressed() { - if (postInfo == null) return; - if (widget.data.username == null) { - _betterPlayerController.pause(); - showAdaptiveActionSheet( - context: context, - title: const Text('You are not logged in. Please log in to comment.'), - androidBorderRadius: 30, - actions: [ - BottomSheetAction( - title: Text('Log in'), - leading: Icon(Icons.login), - onPressed: (c) { - Navigator.of(c).pop(); - var screen = HiveAuthLoginScreen(appData: widget.data); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(c).push(route); - }), - ], - cancelAction: CancelAction(title: const Text('Cancel')), - ); - return; - } - _betterPlayerController.pause(); - var screen = HiveCommentDialog( - author: widget.item.author?.username ?? 'sagarkothari88', - permlink: widget.item.permlink ?? 'ctbtwcxbbd', - username: widget.data.username ?? "", - hasKey: widget.data.keychainData?.hasId ?? "", - hasAuthKey: widget.data.keychainData?.hasAuthKey ?? "", - onClose: () {}, - onDone: (comment) { - loadHiveInfo(); - }, - ); - Navigator.of(context).push(MaterialPageRoute(builder: (c) => screen)); - } - List _fabButtonsOnRight() { final VideoFavoriteProvider provider = VideoFavoriteProvider(); return [ @@ -342,17 +310,11 @@ class _StoryPlayerState extends State { Navigator.of(context).push(route); }, ), - IconButton( - icon: Icon(Icons.notes, color: Colors.blue), - onPressed: () { - seeCommentsPressed(); - }, - ), SizedBox(height: 10), IconButton( icon: Icon(Icons.comment, color: Colors.blue), onPressed: () { - commentPressed(); + seeCommentsPressed(); }, ), SizedBox(height: 10), @@ -362,7 +324,8 @@ class _StoryPlayerState extends State { upvotePressed(); } }, - icon: Icon(Icons.thumb_up, color: Colors.blue), + icon: Icon(isVoted ? Icons.thumb_up : Icons.thumb_up_outlined, + color: Colors.blue), ), SizedBox(height: 10), IconButton( @@ -385,6 +348,18 @@ class _StoryPlayerState extends State { ]; } + bool get isVoted { + if (widget.data.username == null) { + return false; + } else if (postInfo != null && + postInfo!.activeVotes + .contains(ActiveVotesItem(voter: widget.data.username!))) { + return true; + } + + return false; + } + @override Widget build(BuildContext context) { return SafeArea( @@ -439,10 +414,22 @@ class _StoryPlayerState extends State { width: 15, ), Expanded( - child: Text( - widget.item.author!.username!, - maxLines: 2, - overflow: TextOverflow.ellipsis, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.item.author!.username!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + Text( + "${timeago.format(widget.item.createdAt!)}", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 12), + ), + ], ), ) ], From a6d947340f5eceddef28b452dda5be4363f73746 Mon Sep 17 00:00:00 2001 From: sagar Date: Mon, 25 Mar 2024 20:18:27 +0530 Subject: [PATCH 388/466] new comment api that fetch all level comments, local comment is added to the list after comment is posted --- .../newest_comment_model.dart | 376 ++++++++++++++++++ .../comment/comment_action_menu.dart | 10 +- .../controller/comment_controller.dart | 83 +++- .../comment/hive_comment.dart | 59 ++- .../comment/hive_comment_dialog.dart | 67 ++-- .../comment/video_details_comments.dart | 45 ++- lib/src/utils/graphql/gql_communicator.dart | 30 +- 7 files changed, 586 insertions(+), 84 deletions(-) create mode 100644 lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart diff --git a/lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart b/lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart new file mode 100644 index 00000000..b0bd30d3 --- /dev/null +++ b/lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart @@ -0,0 +1,376 @@ +import 'dart:convert'; + +class CommentResponseModel { + final String? jsonrpc; + final List comments; + final int? id; + + CommentResponseModel({ + this.jsonrpc, + this.comments = const [], + this.id, + }); + + factory CommentResponseModel.fromRawJson(String str) => + CommentResponseModel.fromJson(json.decode(str)); + + factory CommentResponseModel.fromJson(Map json) => + CommentResponseModel( + jsonrpc: json["jsonrpc"], + comments: _parseComments(json["result"]), + id: json["id"], + ); + + static List _parseComments(Map? json) { + List items = []; + if (json != null) { + int count = 0; + json.forEach((key, value) { + if (count != 0) { + items.add(CommentItemModel.fromJson(value)); + } + count++; + }); + ; + } + return items; + } +} + +class CommentItemModel { + final int? postId; + final String author; + final String permlink; + final String? category; + final String? title; + final String body; + final CommentMetaDataModel? jsonMetadata; + final DateTime created; + final DateTime? updated; + final int depth; + final int children; + final int? netRshares; + final bool? isPaidout; + final DateTime? payoutAt; + final double? payout; + final String? pendingPayoutValue; + final String? authorPayoutValue; + final String? curatorPayoutValue; + final String? promoted; + final List replies; + final int? reblogs; + final double? authorReputation; + final Stats? stats; + final String? url; + final List? beneficiaries; + final String? maxAcceptedPayout; + final int? percentHbd; + final String? parentAuthor; + final String? parentPermlink; + final List activeVotes; + final List blacklists; + final String? community; + final String? communityTitle; + final String? authorRole; + final String? authorTitle; + var visited = false; + + CommentItemModel({ + this.postId, + required this.author, + required this.permlink, + this.category, + this.title, + required this.body, + this.jsonMetadata, + required this.created, + this.updated, + required this.depth, + required this.children, + this.netRshares, + this.isPaidout, + this.payoutAt, + this.payout, + this.pendingPayoutValue, + this.authorPayoutValue, + this.curatorPayoutValue, + this.promoted, + this.replies = const [], + this.reblogs, + this.authorReputation, + this.stats, + this.url, + this.beneficiaries, + this.maxAcceptedPayout, + this.percentHbd, + this.parentAuthor, + this.parentPermlink, + this.activeVotes = const [], + this.blacklists = const [], + this.community, + this.communityTitle, + this.authorRole, + this.authorTitle, + }); + + CommentItemModel copyWith({ + int? postId, + String? author, + String? permlink, + String? category, + String? title, + String? body, + CommentMetaDataModel? jsonMetadata, + DateTime? created, + DateTime? updated, + int? depth, + int? children, + int? netRshares, + bool? isPaidout, + DateTime? payoutAt, + double? payout, + String? pendingPayoutValue, + String? authorPayoutValue, + String? curatorPayoutValue, + String? promoted, + List? replies, + int? reblogs, + double? authorReputation, + Stats? stats, + String? url, + List? beneficiaries, + String? maxAcceptedPayout, + int? percentHbd, + String? parentAuthor, + String? parentPermlink, + List? activeVotes, + List? blacklists, + String? community, + String? communityTitle, + String? authorRole, + String? authorTitle, +}) { + return CommentItemModel( + postId: postId ?? this.postId, + author: author ?? this.author, + permlink: permlink ?? this.permlink, + category: category ?? this.category, + title: title ?? this.title, + body: body ?? this.body, + jsonMetadata: jsonMetadata ?? this.jsonMetadata, + created: created ?? this.created, + updated: updated ?? this.updated, + depth: depth ?? this.depth, + children: children ?? this.children, + netRshares: netRshares ?? this.netRshares, + isPaidout: isPaidout ?? this.isPaidout, + payoutAt: payoutAt ?? this.payoutAt, + payout: payout ?? this.payout, + pendingPayoutValue: pendingPayoutValue ?? this.pendingPayoutValue, + authorPayoutValue: authorPayoutValue ?? this.authorPayoutValue, + curatorPayoutValue: curatorPayoutValue ?? this.curatorPayoutValue, + promoted: promoted ?? this.promoted, + replies: replies ?? this.replies, + reblogs: reblogs ?? this.reblogs, + authorReputation: authorReputation ?? this.authorReputation, + stats: stats ?? this.stats, + url: url ?? this.url, + beneficiaries: beneficiaries ?? this.beneficiaries, + maxAcceptedPayout: maxAcceptedPayout ?? this.maxAcceptedPayout, + percentHbd: percentHbd ?? this.percentHbd, + parentAuthor: parentAuthor ?? this.parentAuthor, + parentPermlink: parentPermlink ?? this.parentPermlink, + activeVotes: activeVotes ?? this.activeVotes, + blacklists: blacklists ?? this.blacklists, + community: community ?? this.community, + communityTitle: communityTitle ?? this.communityTitle, + authorRole: authorRole ?? this.authorRole, + authorTitle: authorTitle ?? this.authorTitle, + ); +} + + + factory CommentItemModel.fromRawJson(String str) => + CommentItemModel.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory CommentItemModel.fromJson(Map json) => + CommentItemModel( + postId: json["post_id"], + author: json["author"], + permlink: json["permlink"], + category: json["category"], + title: json["title"], + body: json["body"], + jsonMetadata: json["json_metadata"] == null + ? null + : CommentMetaDataModel.fromJson(json["json_metadata"]), + created: DateTime.parse(json["created"]), + updated: + json["updated"] == null ? null : DateTime.parse(json["updated"]), + depth: json["depth"], + children: json["children"], + netRshares: json["net_rshares"], + isPaidout: json["is_paidout"], + payoutAt: json["payout_at"] == null + ? null + : DateTime.parse(json["payout_at"]), + payout: json["payout"]?.toDouble(), + pendingPayoutValue: json["pending_payout_value"], + authorPayoutValue: json["author_payout_value"], + curatorPayoutValue: json["curator_payout_value"], + promoted: json["promoted"], + replies: json["replies"] == null + ? [] + : List.from(json["replies"]!.map((x) => x)), + reblogs: json["reblogs"], + authorReputation: json["author_reputation"]?.toDouble(), + stats: json["stats"] == null ? null : Stats.fromJson(json["stats"]), + url: json["url"], + beneficiaries: json["beneficiaries"] == null + ? [] + : List.from(json["beneficiaries"]!.map((x) => x)), + maxAcceptedPayout: json["max_accepted_payout"], + percentHbd: json["percent_hbd"], + parentAuthor: json["parent_author"], + parentPermlink: json["parent_permlink"], + activeVotes: json["active_votes"] == null + ? [] + : List.from(json["active_votes"]! + .map((x) => CommentActiveVote.fromJson(x))), + blacklists: json["blacklists"] == null + ? [] + : List.from(json["blacklists"]!.map((x) => x)), + community: json["community"], + communityTitle: json["community_title"], + authorRole: json["author_role"], + authorTitle: json["author_title"], + ); + + Map toJson() => { + "post_id": postId, + "author": author, + "permlink": permlink, + "category": category, + "title": title, + "body": body, + "json_metadata": jsonMetadata?.toJson(), + "created": created.toIso8601String(), + "updated": updated?.toIso8601String(), + "depth": depth, + "children": children, + "net_rshares": netRshares, + "is_paidout": isPaidout, + "payout_at": payoutAt?.toIso8601String(), + "payout": payout, + "pending_payout_value": pendingPayoutValue, + "author_payout_value": authorPayoutValue, + "curator_payout_value": curatorPayoutValue, + "promoted": promoted, + "replies": List.from(replies.map((x) => x)), + "reblogs": reblogs, + "author_reputation": authorReputation, + "stats": stats?.toJson(), + "url": url, + "beneficiaries": beneficiaries == null + ? [] + : List.from(beneficiaries!.map((x) => x)), + "max_accepted_payout": maxAcceptedPayout, + "percent_hbd": percentHbd, + "parent_author": parentAuthor, + "parent_permlink": parentPermlink, + "active_votes": List.from(activeVotes!.map((x) => x.toJson())), + "blacklists": List.from(blacklists!.map((x) => x)), + "community": community, + "community_title": communityTitle, + "author_role": authorRole, + "author_title": authorTitle, + }; +} + +class CommentActiveVote { + final int? rshares; + final String? voter; + + CommentActiveVote({ + this.rshares, + this.voter, + }); + + factory CommentActiveVote.fromRawJson(String str) => + CommentActiveVote.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory CommentActiveVote.fromJson(Map json) => + CommentActiveVote( + rshares: json["rshares"], + voter: json["voter"], + ); + + Map toJson() => { + "rshares": rshares, + "voter": voter, + }; +} + +class CommentMetaDataModel { + final List? tags; + final String? app; + + CommentMetaDataModel({ + this.tags, + this.app, + }); + + factory CommentMetaDataModel.fromRawJson(String str) => + CommentMetaDataModel.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory CommentMetaDataModel.fromJson(Map json) => + CommentMetaDataModel( + tags: json["tags"] == null + ? [] + : List.from(json["tags"]!.map((x) => x)), + app: json["app"], + ); + + Map toJson() => { + "tags": tags == null ? [] : List.from(tags!.map((x) => x)), + "app": app, + }; +} + +class Stats { + final bool? hide; + final bool? gray; + final int? totalVotes; + final double? flagWeight; + + Stats({ + this.hide, + this.gray, + this.totalVotes, + this.flagWeight, + }); + + factory Stats.fromRawJson(String str) => Stats.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Stats.fromJson(Map json) => Stats( + hide: json["hide"], + gray: json["gray"], + totalVotes: json["total_votes"], + flagWeight: json["flag_weight"], + ); + + Map toJson() => { + "hide": hide, + "gray": gray, + "total_votes": totalVotes, + "flag_weight": flagWeight, + }; +} diff --git a/lib/src/screens/video_details_screen/comment/comment_action_menu.dart b/lib/src/screens/video_details_screen/comment/comment_action_menu.dart index 465cdc48..7b66398e 100644 --- a/lib/src/screens/video_details_screen/comment/comment_action_menu.dart +++ b/lib/src/screens/video_details_screen/comment/comment_action_menu.dart @@ -1,3 +1,4 @@ +import 'package:acela/src/models/hive_comments/new_hive_comment/newest_comment_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/login/ha_login_screen.dart'; import 'package:acela/src/screens/video_details_screen/comment/hive_comment_dialog.dart'; @@ -14,14 +15,16 @@ class CommentActionMenu extends StatelessWidget { required this.author, required this.permlink, required this.onUpVote, + required this.depth, required this.onSubCommentAdded}) : super(key: key); final HiveUserData appData; final String author; final String permlink; + final int depth; final VoidCallback onUpVote; - final VoidCallback onSubCommentAdded; + final Function(CommentItemModel) onSubCommentAdded; @override Widget build(BuildContext context) { @@ -95,12 +98,15 @@ class CommentActionMenu extends StatelessWidget { var screen = HiveCommentDialog( author: author, permlink: permlink, + depth:depth , username: appData.username ?? "", hasKey: appData.keychainData?.hasId ?? "", hasAuthKey: appData.keychainData?.hasAuthKey ?? "", onClose: () {}, onDone: (newComment) async { - onSubCommentAdded(); + if(newComment!=null){ + onSubCommentAdded(newComment); + } }, ); Navigator.of(context).push(MaterialPageRoute(builder: (c) => screen)); diff --git a/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart b/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart index 39c315c1..8515478b 100644 --- a/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart +++ b/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart @@ -1,4 +1,7 @@ +import 'dart:developer'; + import 'package:acela/src/models/hive_comments/new_hive_comment/new_hive_comment.dart'; +import 'package:acela/src/models/hive_comments/new_hive_comment/newest_comment_model.dart'; import 'package:acela/src/utils/enum.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:flutter/material.dart'; @@ -6,7 +9,7 @@ import 'package:flutter/material.dart'; class CommentController extends ChangeNotifier { final GQLCommunicator _gqlCommunicator = GQLCommunicator(); ViewState viewState = ViewState.loading; - List items = []; + List items = []; final String author; final String permlink; @@ -17,7 +20,14 @@ class CommentController extends ChangeNotifier { void _init() async { try { - items = [...await _gqlCommunicator.getHiveComments(author, permlink)]; + items = [...await _gqlCommunicator.getComments(author, permlink)]; + log(author); + log(permlink); + items = refactorComments(items, permlink); + items.forEach((element) { + print( + "author- ${element.author} parentAuthor- ${element.parentAuthor} parentpermlink- ${element.parentPermlink} permlink- ${element.permlink}"); + }); if (items.isEmpty) { viewState = ViewState.empty; } else { @@ -30,13 +40,27 @@ class CommentController extends ChangeNotifier { } } - void addComment(VideoCommentModel comment) { - items = [...items, comment]; + void addTopLevelComment(CommentItemModel comment) { + items = [ + comment, + ...items, + ]; + notifyListeners(); + } + + void addSubLevelComment(CommentItemModel comment, int index) { + items.insert(index + 1, comment); + items = [ + ...items, + ]; + log('localy added'); notifyListeners(); } - void onUpvote(VideoCommentModel comment, int index) { - items[index] = comment.copyWith(numVotes: comment.stats!.numVotes! + 1); + void onUpvote(CommentItemModel comment, int index) { + items[index] = comment.copyWith(activeVotes: [ + ...comment.activeVotes, + ]); notifyListeners(); } @@ -45,4 +69,51 @@ class CommentController extends ChangeNotifier { notifyListeners(); _init(); } + + static List refactorComments( + List content, String parentPermlink) { + List refactoredComments = []; + var newContent = List.from(content); + for (var e in newContent) { + e.visited = false; + } + newContent.sort((a, b) { + var bTime = b.created; + var aTime = a.created; + if (aTime.isAfter(bTime)) { + return -1; + } else if (bTime.isAfter(aTime)) { + return 1; + } else { + return 0; + } + }); + refactoredComments.addAll( + newContent.where((e) => e.parentPermlink == parentPermlink).toList()); + while (refactoredComments.where((e) => e.visited == false).isNotEmpty) { + var firstComment = + refactoredComments.where((e) => e.visited == false).first; + var indexOfFirstElement = refactoredComments.indexOf(firstComment); + if (firstComment.children != 0) { + List children = newContent + .where((e) => e.parentPermlink == firstComment.permlink) + .toList(); + children.sort((a, b) { + var aTime = a.created; + var bTime = b.created; + if (aTime.isAfter(bTime)) { + return -1; + } else if (bTime.isAfter(aTime)) { + return 1; + } else { + return 0; + } + }); + refactoredComments.insertAll(indexOfFirstElement + 1, children); + } + firstComment.visited = true; + } + log('Returning ${refactoredComments.length} elements'); + return refactoredComments; + } } diff --git a/lib/src/screens/video_details_screen/comment/hive_comment.dart b/lib/src/screens/video_details_screen/comment/hive_comment.dart index c3f798b7..ced86b71 100644 --- a/lib/src/screens/video_details_screen/comment/hive_comment.dart +++ b/lib/src/screens/video_details_screen/comment/hive_comment.dart @@ -1,4 +1,4 @@ -import 'package:acela/src/models/hive_comments/new_hive_comment/new_hive_comment.dart'; +import 'package:acela/src/models/hive_comments/new_hive_comment/newest_comment_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/video_details_screen/comment/comment_action_menu.dart'; import 'package:acela/src/screens/video_details_screen/comment/controller/comment_controller.dart'; @@ -11,8 +11,11 @@ import 'package:timeago/timeago.dart' as timeago; import 'package:url_launcher/url_launcher.dart'; class HiveCommentWidget extends StatefulWidget { - const HiveCommentWidget({Key? key, required this.comment}) : super(key: key); - final VideoCommentModel comment; + const HiveCommentWidget( + {Key? key, required this.comment, required this.index}) + : super(key: key); + final CommentItemModel comment; + final int index; @override State createState() => _HiveCommentWidgetState(); @@ -21,35 +24,21 @@ class HiveCommentWidget extends StatefulWidget { class _HiveCommentWidgetState extends State { @override Widget build(BuildContext context) { - return Column( - children: [ - CommentTile( - comment: widget.comment, - isPadded: false, - ), - Visibility( - visible: widget.comment.children!.isNotEmpty, - child: Column( - children: List.generate( - widget.comment.children!.length, - (index) => CommentTile( - comment: widget.comment.children![index], - isPadded: true, - ), - ), - ), - ), - ], + return CommentTile( + comment: widget.comment, + isPadded: widget.comment.depth != 1, + index: widget.index, ); } } class CommentTile extends StatefulWidget { - const CommentTile({Key? key, required this.comment, required this.isPadded}) + const CommentTile({Key? key, required this.comment, required this.isPadded, required this.index}) : super(key: key); - final VideoCommentModel comment; + final CommentItemModel comment; final bool isPadded; + final int index; @override State createState() => _CommentTileState(); @@ -61,7 +50,7 @@ class _CommentTileState extends State @override void initState() { - votes = widget.comment.stats!.numVotes!; + votes = widget.comment.stats?.totalVotes ?? 0; super.initState(); } @@ -69,13 +58,12 @@ class _CommentTileState extends State Widget build(BuildContext context) { super.build(context); var item = widget.comment; - var author = item.author.username; + var author = item.author; var body = item.body; - var timeInString = - item.createdAt != null ? "${timeago.format(item.createdAt!)}" : ""; + var timeInString = "${timeago.format(item.created)}"; var depth = (widget.isPadded ? 50.0 : 0.2 * 25.0); var style = TextStyle(color: Colors.white, fontWeight: FontWeight.w600); - return GestureDetector( + return InkWell( onTap: () { _showBottomSheet(item, () { setState(() { @@ -95,7 +83,7 @@ class _CommentTileState extends State children: [ Row( children: [ - UserProfileImage(userName: item.author.username), + UserProfileImage(userName: item.author), const SizedBox( width: 8, ), @@ -139,7 +127,7 @@ class _CommentTileState extends State const SizedBox( height: 8, ), - _comment(body ?? ""), + _comment(body), ], ), ), @@ -156,7 +144,7 @@ class _CommentTileState extends State ); } - void _showBottomSheet(VideoCommentModel item, VoidCallback onUpvote) { + void _showBottomSheet(CommentItemModel item, VoidCallback onUpvote) { final controller = context.read(); showModalBottomSheet( backgroundColor: const Color(0xFF1B1A1A), @@ -165,10 +153,13 @@ class _CommentTileState extends State borderRadius: BorderRadius.all(Radius.circular(12))), context: context, builder: (context) => CommentActionMenu( - onSubCommentAdded: controller.refreshSilently, + depth: item.depth, + onSubCommentAdded: (newComment) { + controller.addSubLevelComment(newComment, widget.index); + }, onUpVote: onUpvote, appData: context.read(), - author: item.author.username, + author: item.author, permlink: item.permlink, ), ); diff --git a/lib/src/screens/video_details_screen/comment/hive_comment_dialog.dart b/lib/src/screens/video_details_screen/comment/hive_comment_dialog.dart index 1686d049..94b45882 100644 --- a/lib/src/screens/video_details_screen/comment/hive_comment_dialog.dart +++ b/lib/src/screens/video_details_screen/comment/hive_comment_dialog.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/models/hive_comments/new_hive_comment/new_hive_comment.dart'; +import 'package:acela/src/models/hive_comments/new_hive_comment/newest_comment_model.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/utils/communicator.dart'; @@ -15,22 +16,24 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; class HiveCommentDialog extends StatefulWidget { - const HiveCommentDialog({ - Key? key, - required this.username, - required this.author, - required this.permlink, - required this.hasKey, - required this.hasAuthKey, - required this.onClose, - required this.onDone, - }) : super(key: key); + const HiveCommentDialog( + {Key? key, + required this.username, + required this.author, + required this.permlink, + required this.hasKey, + required this.hasAuthKey, + required this.onClose, + required this.onDone, + this.depth}) + : super(key: key); final String username; final String author; final String permlink; final String hasKey; final String hasAuthKey; - final Function(VideoCommentModel? comment) onDone; + final int? depth; + final Function(CommentItemModel? comment) onDone; final Function onClose; @override @@ -127,15 +130,18 @@ class _HiveCommentDialogState extends State { Future.delayed(const Duration(seconds: 6), () { if (mounted) { setState(() { - VideoCommentModel addedComment = VideoCommentModel( - createdAt: DateTime.now(), - author: VideoCommentAuthorModel(username: widget.author), - permlink: widget.permlink, - body: textController.text, - stats: VideoCommentStatsModel( - numVotes: 0, - ), - children: []); + String currentUserName = widget.username; + CommentItemModel addedComment = CommentItemModel( + created: DateTime.now(), + author: currentUserName, + permlink: + "re-$currentUserName-${DateTime.now().toIso8601String()}", + parentAuthor: widget.author, + parentPermlink: widget.permlink, + body: textController.text, + depth: widget.depth == null ? 1 : widget.depth! + 1, + children: 0, + ); isCommenting = false; widget.onDone(addedComment); Navigator.of(context).pop(); @@ -236,15 +242,18 @@ class _HiveCommentDialogState extends State { if (mounted) { setState(() { isCommenting = false; - VideoCommentModel addedComment = VideoCommentModel( - createdAt: DateTime.now(), - author: VideoCommentAuthorModel(username: widget.author), - permlink: widget.permlink, - body: textController.text, - stats: VideoCommentStatsModel( - numVotes: 0, - ), - children: []); + String currentUserName = widget.username; + CommentItemModel addedComment = CommentItemModel( + created: DateTime.now(), + author: currentUserName, + permlink: + "re-$currentUserName-${DateTime.now().toIso8601String()}", + parentAuthor: widget.author, + parentPermlink: widget.permlink, + body: textController.text, + depth: widget.depth == null ? 1 : widget.depth! + 1, + children: 0, + ); widget.onDone(addedComment); showMessage('Comment published successfully'); Navigator.of(context).pop(); diff --git a/lib/src/screens/video_details_screen/comment/video_details_comments.dart b/lib/src/screens/video_details_screen/comment/video_details_comments.dart index 25fc3d92..b4f81970 100644 --- a/lib/src/screens/video_details_screen/comment/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/comment/video_details_comments.dart @@ -1,5 +1,4 @@ - -import 'package:acela/src/models/hive_comments/new_hive_comment/new_hive_comment.dart'; +import 'package:acela/src/models/hive_comments/new_hive_comment/newest_comment_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/login/ha_login_screen.dart'; import 'package:acela/src/screens/video_details_screen/comment/controller/comment_controller.dart'; @@ -37,8 +36,8 @@ class _VideoDetailsCommentsState extends State { } Widget commentsListView(CommentController controller) { - return Selector>( - shouldRebuild: (previous,next)=>true, + return Selector>( + shouldRebuild: (previous, next) => true, selector: (_, myType) => myType.items, builder: (context, items, child) { return Column( @@ -49,13 +48,23 @@ class _VideoDetailsCommentsState extends State { margin: const EdgeInsets.only(top: 10, bottom: 10), child: ListView.separated( itemBuilder: (context, index) { - final VideoCommentModel item = items[index]; - return HiveCommentWidget(comment: item); + final CommentItemModel item = items[index]; + return HiveCommentWidget( + key: ValueKey('${item.author}/${item.permlink}'), + comment: item,index: index,); + }, + separatorBuilder: (context, index) { + bool commentDividerVisibility = true; + commentDividerVisibility = _commentDividerVisibility( + index, items, commentDividerVisibility); + return Visibility( + visible: commentDividerVisibility, + child: const Divider( + height: 10, + color: Colors.blueGrey, + ), + ); }, - separatorBuilder: (context, index) => const Divider( - height: 10, - color: Colors.blueGrey, - ), itemCount: items.length, ), ), @@ -67,6 +76,18 @@ class _VideoDetailsCommentsState extends State { ); } + bool _commentDividerVisibility( + int index, List items, bool drawLine) { + if (index + 1 < items.length) { + if ((items[index + 1].depth == 1)) { + drawLine = true; + } else { + drawLine = false; + } + } + return drawLine; + } + Widget _addCommentButton(CommentController controller) { return Padding( padding: const EdgeInsets.only(left: 10.0, right: 10, bottom: 10), @@ -125,8 +146,8 @@ class _VideoDetailsCommentsState extends State { hasAuthKey: widget.appData.keychainData?.hasAuthKey ?? "", onClose: () {}, onDone: (newComment) async { - if(newComment!=null){ - controller.addComment(newComment); + if (newComment != null) { + controller.addTopLevelComment(newComment); } }, ); diff --git a/lib/src/utils/graphql/gql_communicator.dart b/lib/src/utils/graphql/gql_communicator.dart index deb36702..ef2bc4d7 100644 --- a/lib/src/utils/graphql/gql_communicator.dart +++ b/lib/src/utils/graphql/gql_communicator.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:developer'; import 'package:acela/src/models/hive_comments/new_hive_comment/new_hive_comment.dart'; +import 'package:acela/src/models/hive_comments/new_hive_comment/newest_comment_model.dart'; import 'package:acela/src/models/trending_tags/trending_tags_response.dart'; import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -221,7 +222,7 @@ class GQLCommunicator { } } - Future getVideoDetails(String author,String permlink) async { + Future getVideoDetails(String author, String permlink) async { var headers = { 'Connection': 'keep-alive', 'content-type': 'application/json', @@ -248,4 +249,31 @@ class GQLCommunicator { throw response.reasonPhrase ?? 'Error occurred'; } } + + Future> getComments( + String author, String permlink) async { + try { + var headers = {'content-type': 'application/json'}; + var request = http.Request('POST', Uri.parse('https://api.hive.blog/')); + request.body = json.encode({ + "id": 9, + "jsonrpc": "2.0", + "method": "bridge.get_discussion", + "params": {"author": author, "permlink": permlink} + }); + request.headers.addAll(headers); + + http.StreamedResponse response = await request.send(); + + if (response.statusCode == 200) { + CommentResponseModel commentResponse = CommentResponseModel.fromRawJson( + await response.stream.bytesToString()); + return commentResponse.comments; + } else { + throw (response.reasonPhrase.toString()); + } + } catch (e) { + throw (e.toString()); + } + } } From ff42ddf00efa13884fd229dc20608c666336436b Mon Sep 17 00:00:00 2001 From: sagar Date: Tue, 26 Mar 2024 20:57:38 +0530 Subject: [PATCH 389/466] comment search,comment highligheter,comment scroll --- .../newest_comment_model.dart | 254 +++++++++-------- .../comment/comment_search_bar.dart | 111 ++++++++ .../comment/comment_view_appbar.dart | 49 ++++ .../controller/comment_controller.dart | 119 ++++++-- .../comment/hive_comment.dart | 260 ++++++++++++------ .../comment/hive_comment_dialog.dart | 4 +- .../comment/video_details_comments.dart | 221 ++++++++++----- pubspec.lock | 36 ++- pubspec.yaml | 1 + 9 files changed, 746 insertions(+), 309 deletions(-) create mode 100644 lib/src/screens/video_details_screen/comment/comment_search_bar.dart create mode 100644 lib/src/screens/video_details_screen/comment/comment_view_appbar.dart diff --git a/lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart b/lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart index b0bd30d3..3fecf375 100644 --- a/lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart +++ b/lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart @@ -1,5 +1,7 @@ import 'dart:convert'; +import 'package:equatable/equatable.dart'; + class CommentResponseModel { final String? jsonrpc; final List comments; @@ -37,7 +39,8 @@ class CommentResponseModel { } } -class CommentItemModel { +// ignore: must_be_immutable +class CommentItemModel extends Equatable { final int? postId; final String author; final String permlink; @@ -74,121 +77,121 @@ class CommentItemModel { final String? authorRole; final String? authorTitle; var visited = false; + final bool isLocallyAdded; - CommentItemModel({ - this.postId, - required this.author, - required this.permlink, - this.category, - this.title, - required this.body, - this.jsonMetadata, - required this.created, - this.updated, - required this.depth, - required this.children, - this.netRshares, - this.isPaidout, - this.payoutAt, - this.payout, - this.pendingPayoutValue, - this.authorPayoutValue, - this.curatorPayoutValue, - this.promoted, - this.replies = const [], - this.reblogs, - this.authorReputation, - this.stats, - this.url, - this.beneficiaries, - this.maxAcceptedPayout, - this.percentHbd, - this.parentAuthor, - this.parentPermlink, - this.activeVotes = const [], - this.blacklists = const [], - this.community, - this.communityTitle, - this.authorRole, - this.authorTitle, - }); + CommentItemModel( + {this.postId, + required this.author, + required this.permlink, + this.category, + this.title, + required this.body, + this.jsonMetadata, + required this.created, + this.updated, + required this.depth, + required this.children, + this.netRshares, + this.isPaidout, + this.payoutAt, + this.payout, + this.pendingPayoutValue, + this.authorPayoutValue, + this.curatorPayoutValue, + this.promoted, + this.replies = const [], + this.reblogs, + this.authorReputation, + this.stats, + this.url, + this.beneficiaries, + this.maxAcceptedPayout, + this.percentHbd, + this.parentAuthor, + this.parentPermlink, + this.activeVotes = const [], + this.blacklists = const [], + this.community, + this.communityTitle, + this.authorRole, + this.authorTitle, + this.isLocallyAdded = false}); CommentItemModel copyWith({ - int? postId, - String? author, - String? permlink, - String? category, - String? title, - String? body, - CommentMetaDataModel? jsonMetadata, - DateTime? created, - DateTime? updated, - int? depth, - int? children, - int? netRshares, - bool? isPaidout, - DateTime? payoutAt, - double? payout, - String? pendingPayoutValue, - String? authorPayoutValue, - String? curatorPayoutValue, - String? promoted, - List? replies, - int? reblogs, - double? authorReputation, - Stats? stats, - String? url, - List? beneficiaries, - String? maxAcceptedPayout, - int? percentHbd, - String? parentAuthor, - String? parentPermlink, - List? activeVotes, - List? blacklists, - String? community, - String? communityTitle, - String? authorRole, - String? authorTitle, -}) { - return CommentItemModel( - postId: postId ?? this.postId, - author: author ?? this.author, - permlink: permlink ?? this.permlink, - category: category ?? this.category, - title: title ?? this.title, - body: body ?? this.body, - jsonMetadata: jsonMetadata ?? this.jsonMetadata, - created: created ?? this.created, - updated: updated ?? this.updated, - depth: depth ?? this.depth, - children: children ?? this.children, - netRshares: netRshares ?? this.netRshares, - isPaidout: isPaidout ?? this.isPaidout, - payoutAt: payoutAt ?? this.payoutAt, - payout: payout ?? this.payout, - pendingPayoutValue: pendingPayoutValue ?? this.pendingPayoutValue, - authorPayoutValue: authorPayoutValue ?? this.authorPayoutValue, - curatorPayoutValue: curatorPayoutValue ?? this.curatorPayoutValue, - promoted: promoted ?? this.promoted, - replies: replies ?? this.replies, - reblogs: reblogs ?? this.reblogs, - authorReputation: authorReputation ?? this.authorReputation, - stats: stats ?? this.stats, - url: url ?? this.url, - beneficiaries: beneficiaries ?? this.beneficiaries, - maxAcceptedPayout: maxAcceptedPayout ?? this.maxAcceptedPayout, - percentHbd: percentHbd ?? this.percentHbd, - parentAuthor: parentAuthor ?? this.parentAuthor, - parentPermlink: parentPermlink ?? this.parentPermlink, - activeVotes: activeVotes ?? this.activeVotes, - blacklists: blacklists ?? this.blacklists, - community: community ?? this.community, - communityTitle: communityTitle ?? this.communityTitle, - authorRole: authorRole ?? this.authorRole, - authorTitle: authorTitle ?? this.authorTitle, - ); -} - + int? postId, + String? author, + String? permlink, + String? category, + String? title, + String? body, + CommentMetaDataModel? jsonMetadata, + DateTime? created, + DateTime? updated, + int? depth, + int? children, + int? netRshares, + bool? isPaidout, + DateTime? payoutAt, + double? payout, + String? pendingPayoutValue, + String? authorPayoutValue, + String? curatorPayoutValue, + String? promoted, + List? replies, + int? reblogs, + double? authorReputation, + Stats? stats, + String? url, + List? beneficiaries, + String? maxAcceptedPayout, + int? percentHbd, + String? parentAuthor, + String? parentPermlink, + List? activeVotes, + List? blacklists, + String? community, + String? communityTitle, + String? authorRole, + String? authorTitle, + }) { + return CommentItemModel( + postId: postId ?? this.postId, + author: author ?? this.author, + permlink: permlink ?? this.permlink, + category: category ?? this.category, + title: title ?? this.title, + body: body ?? this.body, + jsonMetadata: jsonMetadata ?? this.jsonMetadata, + created: created ?? this.created, + updated: updated ?? this.updated, + depth: depth ?? this.depth, + children: children ?? this.children, + netRshares: netRshares ?? this.netRshares, + isPaidout: isPaidout ?? this.isPaidout, + payoutAt: payoutAt ?? this.payoutAt, + payout: payout ?? this.payout, + pendingPayoutValue: pendingPayoutValue ?? this.pendingPayoutValue, + authorPayoutValue: authorPayoutValue ?? this.authorPayoutValue, + curatorPayoutValue: curatorPayoutValue ?? this.curatorPayoutValue, + promoted: promoted ?? this.promoted, + replies: replies ?? this.replies, + reblogs: reblogs ?? this.reblogs, + authorReputation: authorReputation ?? this.authorReputation, + stats: stats ?? this.stats, + url: url ?? this.url, + beneficiaries: beneficiaries ?? this.beneficiaries, + maxAcceptedPayout: maxAcceptedPayout ?? this.maxAcceptedPayout, + percentHbd: percentHbd ?? this.percentHbd, + parentAuthor: parentAuthor ?? this.parentAuthor, + parentPermlink: parentPermlink ?? this.parentPermlink, + activeVotes: activeVotes ?? this.activeVotes, + blacklists: blacklists ?? this.blacklists, + community: community ?? this.community, + communityTitle: communityTitle ?? this.communityTitle, + authorRole: authorRole ?? this.authorRole, + authorTitle: authorTitle ?? this.authorTitle, + ); + } factory CommentItemModel.fromRawJson(String str) => CommentItemModel.fromJson(json.decode(str)); @@ -280,16 +283,20 @@ class CommentItemModel { "percent_hbd": percentHbd, "parent_author": parentAuthor, "parent_permlink": parentPermlink, - "active_votes": List.from(activeVotes!.map((x) => x.toJson())), + "active_votes": List.from(activeVotes!.map((x) => x.toJson())), "blacklists": List.from(blacklists!.map((x) => x)), "community": community, "community_title": communityTitle, "author_role": authorRole, "author_title": authorTitle, }; + + @override + List get props => + [postId, permlink, author, parentPermlink, parentAuthor, created]; } -class CommentActiveVote { +class CommentActiveVote extends Equatable { final int? rshares; final String? voter; @@ -313,6 +320,9 @@ class CommentActiveVote { "rshares": rshares, "voter": voter, }; + + @override + List get props => [voter]; } class CommentMetaDataModel { @@ -356,6 +366,20 @@ class Stats { this.flagWeight, }); + Stats copyWith({ + bool? hide, + bool? gray, + int? totalVotes, + double? flagWeight, + }) { + return Stats( + hide: hide ?? this.hide, + gray: gray ?? this.gray, + totalVotes: totalVotes ?? this.totalVotes, + flagWeight: flagWeight ?? this.flagWeight, + ); + } + factory Stats.fromRawJson(String str) => Stats.fromJson(json.decode(str)); String toRawJson() => json.encode(toJson()); diff --git a/lib/src/screens/video_details_screen/comment/comment_search_bar.dart b/lib/src/screens/video_details_screen/comment/comment_search_bar.dart new file mode 100644 index 00000000..1f6c8178 --- /dev/null +++ b/lib/src/screens/video_details_screen/comment/comment_search_bar.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; + +class CommentSearchBar extends StatefulWidget { + const CommentSearchBar( + {required this.onChanged, + required this.textEditingController, + required this.showSearchBar}); + + final Function(String value) onChanged; + final TextEditingController textEditingController; + final ValueNotifier showSearchBar; + @override + State createState() => _CommentSearchBarState(); +} + +class _CommentSearchBarState extends State { + late FocusNode _focusNode; + + @override + void initState() { + super.initState(); + _focusNode = FocusNode(); + } + + @override + void dispose() { + _focusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final border = outLineBorder(); + final theme = Theme.of(context); + return ValueListenableBuilder( + valueListenable: widget.showSearchBar, + builder: (context, showSearchBar, child) { + if (showSearchBar) { + _focusNode.requestFocus(); + } else { + _focusNode.unfocus(); + } + return PopScope( + canPop: !showSearchBar, + onPopInvoked: (didPop) { + if (showSearchBar) { + _onClear(); + return; + } + }, + child: Column( + children: [ + AnimatedContainer( + height: showSearchBar ? 50 : 0, + duration: const Duration(milliseconds: 250), + padding: const EdgeInsets.only( + left: 8, right: 8, top: 8, bottom: 4), + child: child!), + Visibility(visible: showSearchBar, child: Divider()), + ], + ), + ); + }, + child: TextField( + focusNode: _focusNode, + controller: widget.textEditingController, + onChanged: widget.onChanged, + decoration: InputDecoration( + prefixIcon: FittedBox( + child: Padding( + padding: const EdgeInsets.all(5.0), + child: Icon( + Icons.search, + ), + ), + ), + hintText: "Search for comment, username", + suffixIcon: getSuffixIcon(theme), + fillColor: Theme.of(context).primaryColorDark, + filled: true, + contentPadding: const EdgeInsets.only(bottom: 13), + border: border, + focusedBorder: border, + enabledBorder: border, + disabledBorder: border, + ), + )); + } + + OutlineInputBorder outLineBorder() { + return const OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.all(Radius.circular(4))); + } + + Widget getSuffixIcon(ThemeData theme) { + return IconButton( + splashRadius: 15, + onPressed: () { + _onClear(); + }, + icon: Text('Done')); + } + + void _onClear() { + _focusNode.unfocus(); + widget.showSearchBar.value = false; + widget.textEditingController.clear(); + widget.onChanged(""); + } +} diff --git a/lib/src/screens/video_details_screen/comment/comment_view_appbar.dart b/lib/src/screens/video_details_screen/comment/comment_view_appbar.dart new file mode 100644 index 00000000..44e8803b --- /dev/null +++ b/lib/src/screens/video_details_screen/comment/comment_view_appbar.dart @@ -0,0 +1,49 @@ +import 'package:acela/src/screens/video_details_screen/comment/controller/comment_controller.dart'; +import 'package:acela/src/utils/enum.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class CommentViewAppbar extends StatefulWidget implements PreferredSizeWidget { + const CommentViewAppbar( + {Key? key, required this.state, required this.showSearchBar}) + : super(key: key); + + final ViewState state; + final ValueNotifier showSearchBar; + + @override + State createState() => _CommentViewAppbarState(); + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); +} + +class _CommentViewAppbarState extends State { + bool showSearch = false; + + @override + Widget build(BuildContext context) { + int numberOfComments = context + .select((value) => value.disPlayedItems.length); + return AppBar( + title: Text( + 'Comments${widget.state != ViewState.loading ? ' ($numberOfComments)' : ''}'), + actions: [ + ValueListenableBuilder( + valueListenable: widget.showSearchBar, + builder: (context, showSearchButton, child) { + return Visibility( + visible: numberOfComments != 0 && !showSearchButton, + child: child!); + }, + child: IconButton( + onPressed: () { + widget.showSearchBar.value = true; + }, + icon: Icon(Icons.search), + ), + ) + ], + ); + } +} diff --git a/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart b/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart index 8515478b..38044e22 100644 --- a/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart +++ b/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart @@ -1,6 +1,5 @@ import 'dart:developer'; -import 'package:acela/src/models/hive_comments/new_hive_comment/new_hive_comment.dart'; import 'package:acela/src/models/hive_comments/new_hive_comment/newest_comment_model.dart'; import 'package:acela/src/utils/enum.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; @@ -9,7 +8,18 @@ import 'package:flutter/material.dart'; class CommentController extends ChangeNotifier { final GQLCommunicator _gqlCommunicator = GQLCommunicator(); ViewState viewState = ViewState.loading; + List disPlayedItems = []; List items = []; + bool _commentHighlighterTrigger = false; + + bool get commentHighlighterTrigger => _commentHighlighterTrigger; + + set commentHighlighterTrigger(value) { + _commentHighlighterTrigger = value; + notifyListeners(); + } + + int? animateToCommentIndex = null; final String author; final String permlink; @@ -20,15 +30,12 @@ class CommentController extends ChangeNotifier { void _init() async { try { - items = [...await _gqlCommunicator.getComments(author, permlink)]; - log(author); - log(permlink); - items = refactorComments(items, permlink); - items.forEach((element) { - print( - "author- ${element.author} parentAuthor- ${element.parentAuthor} parentpermlink- ${element.parentPermlink} permlink- ${element.permlink}"); - }); - if (items.isEmpty) { + disPlayedItems = [ + ...await _gqlCommunicator.getComments(author, permlink) + ]; + disPlayedItems = refactorComments(disPlayedItems, permlink); + items = disPlayedItems; + if (disPlayedItems.isEmpty) { viewState = ViewState.empty; } else { viewState = ViewState.data; @@ -40,27 +47,75 @@ class CommentController extends ChangeNotifier { } } - void addTopLevelComment(CommentItemModel comment) { + void addTopLevelComment(CommentItemModel comment, String searchKey) { + if (viewState == ViewState.empty) { + viewState = ViewState.data; + } items = [ comment, ...items, ]; + items = refactorComments(items, permlink); + if (searchKey.isEmpty) { + disPlayedItems = items; + } else { + animateToCommentIndex = 0; + if (_isSearchedKeyPresent(comment, searchKey)) { + disPlayedItems = [comment, ...disPlayedItems]; + } + } notifyListeners(); } - void addSubLevelComment(CommentItemModel comment, int index) { - items.insert(index + 1, comment); - items = [ - ...items, - ]; - log('localy added'); + void addSubLevelComment( + CommentItemModel comment, int index, String searchKey) { + if (searchKey.isNotEmpty) { + var item = disPlayedItems[index]; + var newIndex = items.indexWhere((element) => element == item); + if (newIndex != -1) { + items[newIndex] = + items[newIndex].copyWith(children: items[newIndex].children + 1); + items = [...items, comment]; + items = refactorComments(items, permlink); + animateToCommentIndex = newIndex + 1; + if (_isSearchedKeyPresent(comment, searchKey)) { + disPlayedItems = [comment, ...disPlayedItems]; + } + } + } else { + disPlayedItems[index] = disPlayedItems[index] + .copyWith(children: disPlayedItems[index].children + 1); + disPlayedItems = [...disPlayedItems, comment]; + disPlayedItems = refactorComments(disPlayedItems, permlink); + items = disPlayedItems; + } notifyListeners(); } - void onUpvote(CommentItemModel comment, int index) { - items[index] = comment.copyWith(activeVotes: [ + void onUpvote( + CommentItemModel comment, int index, String userName, String searchKey) { + CommentItemModel mutatedComment = comment.copyWith(activeVotes: [ ...comment.activeVotes, + CommentActiveVote(voter: userName) ]); + if (comment.stats != null) { + mutatedComment = mutatedComment.copyWith( + stats: mutatedComment.stats!.copyWith( + totalVotes: (mutatedComment.stats!.totalVotes ?? 0) + 1)); + } + + if (searchKey.isNotEmpty) { + var item = disPlayedItems[index]; + disPlayedItems[index] = mutatedComment; + var newIndex = items.indexWhere((element) => element == item); + if (newIndex != -1) { + items[newIndex] = mutatedComment; + } + } else { + disPlayedItems[index] = mutatedComment; + items = disPlayedItems; + } + notifyListeners(); } @@ -116,4 +171,30 @@ class CommentController extends ChangeNotifier { log('Returning ${refactoredComments.length} elements'); return refactoredComments; } + + void onSearch(String keyword) { + Set data = {}; + if (keyword.isNotEmpty) { + for (CommentItemModel item in items) { + if (_isSearchedKeyPresent(item, keyword)) { + data.add(item); + } + } + disPlayedItems = data.toList(); + notifyListeners(); + } else { + disPlayedItems = items; + notifyListeners(); + } + } + + bool _isSearchedKeyPresent(CommentItemModel item, String keyword) { + if (item.body.toLowerCase().contains(keyword.toLowerCase())) { + return true; + } + if (item.author.toLowerCase().contains(keyword.toLowerCase())) { + return true; + } + return false; + } } diff --git a/lib/src/screens/video_details_screen/comment/hive_comment.dart b/lib/src/screens/video_details_screen/comment/hive_comment.dart index ced86b71..9c1659d7 100644 --- a/lib/src/screens/video_details_screen/comment/hive_comment.dart +++ b/lib/src/screens/video_details_screen/comment/hive_comment.dart @@ -7,38 +7,27 @@ import 'package:acela/src/widgets/user_profile_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:provider/provider.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:timeago/timeago.dart' as timeago; import 'package:url_launcher/url_launcher.dart'; -class HiveCommentWidget extends StatefulWidget { - const HiveCommentWidget( - {Key? key, required this.comment, required this.index}) - : super(key: key); - final CommentItemModel comment; - final int index; - - @override - State createState() => _HiveCommentWidgetState(); -} - -class _HiveCommentWidgetState extends State { - @override - Widget build(BuildContext context) { - return CommentTile( - comment: widget.comment, - isPadded: widget.comment.depth != 1, - index: widget.index, - ); - } -} - class CommentTile extends StatefulWidget { - const CommentTile({Key? key, required this.comment, required this.isPadded, required this.index}) + const CommentTile( + {Key? key, + required this.comment, + required this.isPadded, + required this.index, + required this.currentUser, + required this.searchKey, + required this.itemScrollController}) : super(key: key); final CommentItemModel comment; final bool isPadded; final int index; + final String currentUser; + final String searchKey; + final ItemScrollController itemScrollController; @override State createState() => _CommentTileState(); @@ -47,13 +36,71 @@ class CommentTile extends StatefulWidget { class _CommentTileState extends State with AutomaticKeepAliveClientMixin { late int votes; + late bool isUpvoted; + bool animate = false; + bool animated = false; + Duration duration = Duration(seconds: 5); + late Color color; @override void initState() { - votes = widget.comment.stats?.totalVotes ?? 0; + _initVoteStatus(); + _initAnimation(); super.initState(); } + void _initAnimation() { + if (!animated) { + Duration difference = DateTime.now().difference(widget.comment.created); + animate = difference.inSeconds < 5; + if (animate) { + color = Colors.grey.shade500; + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + if (mounted) + setState(() { + color = Colors.transparent; + animated = true; + animate = false; + }); + }); + } else { + color = Colors.transparent; + } + } else { + color = Colors.transparent; + } + } + + void _callbackToAnimate() { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + if (mounted) + setState(() { + duration = Duration.zero; + color = Colors.grey.shade500; + }); + await Future.delayed(Duration(milliseconds: 50)); + if (mounted) + setState(() { + duration = Duration(seconds: 5); + color = Colors.transparent; + animated = true; + animate = false; + }); + }); + } + + void _initVoteStatus() { + votes = widget.comment.stats?.totalVotes ?? 0; + isUpvoted = widget.comment.activeVotes + .contains(CommentActiveVote(voter: widget.currentUser)); + } + + @override + void didUpdateWidget(covariant CommentTile oldWidget) { + _initVoteStatus(); + super.didUpdateWidget(oldWidget); + } + @override Widget build(BuildContext context) { super.build(context); @@ -63,72 +110,90 @@ class _CommentTileState extends State var timeInString = "${timeago.format(item.created)}"; var depth = (widget.isPadded ? 50.0 : 0.2 * 25.0); var style = TextStyle(color: Colors.white, fontWeight: FontWeight.w600); - return InkWell( - onTap: () { - _showBottomSheet(item, () { - setState(() { - votes++; - }); - }); + return Selector( + selector: (_, provider) => provider.commentHighlighterTrigger, + builder: (context, value, child) { + final controller = context.read(); + if (widget.index == controller.animateToCommentIndex && value) { + _callbackToAnimate(); + controller.animateToCommentIndex = null; + controller.commentHighlighterTrigger = false; + } + return child!; }, - child: Container( - color: Colors.transparent, - padding: EdgeInsets.only( - left: depth + 15, - right: 15, - bottom: 15, - top: widget.isPadded ? 0 : 15), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - UserProfileImage(userName: item.author), - const SizedBox( - width: 8, - ), - Expanded( - child: Row( - children: [ - Text(author, style: style), - const SizedBox( - width: 12, - ), - Icon( - Icons.thumb_up, - size: 15, - ), - const SizedBox( - width: 5, - ), - Text(votes.toString(), style: style), - const SizedBox( - width: 12, - ), - Icon( - Icons.schedule, - size: 15, - ), - const SizedBox( - width: 5, - ), - Expanded( - child: Text( - timeInString, - style: style, - overflow: TextOverflow.ellipsis, - maxLines: 1, - )), - ], + child: InkWell( + onTap: () { + if (!widget.comment.isLocallyAdded) { + _showBottomSheet(item, onUpvote: () { + context.read().onUpvote( + item, widget.index, widget.currentUser, widget.searchKey); + setState(() { + votes++; + isUpvoted = true; + }); + }); + } + }, + child: AnimatedContainer( + duration: duration, + color: color, + padding: EdgeInsets.only( + left: depth + 15, + right: 15, + bottom: 15, + top: widget.isPadded ? 0 : 15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + UserProfileImage(userName: item.author), + const SizedBox( + width: 8, ), - ) - ], - ), - const SizedBox( - height: 8, - ), - _comment(body), - ], + Expanded( + child: Row( + children: [ + Text(author, style: style), + const SizedBox( + width: 12, + ), + Icon( + isUpvoted ? Icons.thumb_up : Icons.thumb_up_outlined, + size: 15, + ), + const SizedBox( + width: 5, + ), + Text(votes.toString(), style: style), + const SizedBox( + width: 12, + ), + Icon( + Icons.schedule, + size: 15, + ), + const SizedBox( + width: 5, + ), + Expanded( + child: Text( + timeInString, + style: style, + overflow: TextOverflow.ellipsis, + maxLines: 1, + )), + ], + ), + ) + ], + ), + const SizedBox( + height: 8, + ), + _comment(body), + ], + ), ), ), ); @@ -144,7 +209,9 @@ class _CommentTileState extends State ); } - void _showBottomSheet(CommentItemModel item, VoidCallback onUpvote) { + void _showBottomSheet(CommentItemModel item, + {required VoidCallback onUpvote}) { + FocusScope.of(context).unfocus(); final controller = context.read(); showModalBottomSheet( backgroundColor: const Color(0xFF1B1A1A), @@ -155,7 +222,13 @@ class _CommentTileState extends State builder: (context) => CommentActionMenu( depth: item.depth, onSubCommentAdded: (newComment) { - controller.addSubLevelComment(newComment, widget.index); + controller.addSubLevelComment( + newComment, widget.index, widget.searchKey); + + if (widget.searchKey.isNotEmpty && + controller.disPlayedItems.contains(newComment)) { + _animteToAddedComment(0); + } }, onUpVote: onUpvote, appData: context.read(), @@ -165,6 +238,13 @@ class _CommentTileState extends State ); } + void _animteToAddedComment(int index) { + widget.itemScrollController.scrollTo( + index: index, + duration: Duration(milliseconds: 200), + curve: Curves.easeInOutCubic); + } + @override bool get wantKeepAlive => true; } diff --git a/lib/src/screens/video_details_screen/comment/hive_comment_dialog.dart b/lib/src/screens/video_details_screen/comment/hive_comment_dialog.dart index 94b45882..eaf3397e 100644 --- a/lib/src/screens/video_details_screen/comment/hive_comment_dialog.dart +++ b/lib/src/screens/video_details_screen/comment/hive_comment_dialog.dart @@ -1,8 +1,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; - -import 'package:acela/src/models/hive_comments/new_hive_comment/new_hive_comment.dart'; import 'package:acela/src/models/hive_comments/new_hive_comment/newest_comment_model.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; @@ -134,6 +132,7 @@ class _HiveCommentDialogState extends State { CommentItemModel addedComment = CommentItemModel( created: DateTime.now(), author: currentUserName, + isLocallyAdded: true, permlink: "re-$currentUserName-${DateTime.now().toIso8601String()}", parentAuthor: widget.author, @@ -245,6 +244,7 @@ class _HiveCommentDialogState extends State { String currentUserName = widget.username; CommentItemModel addedComment = CommentItemModel( created: DateTime.now(), + isLocallyAdded: true, author: currentUserName, permlink: "re-$currentUserName-${DateTime.now().toIso8601String()}", diff --git a/lib/src/screens/video_details_screen/comment/video_details_comments.dart b/lib/src/screens/video_details_screen/comment/video_details_comments.dart index b4f81970..f43e1d67 100644 --- a/lib/src/screens/video_details_screen/comment/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/comment/video_details_comments.dart @@ -1,6 +1,8 @@ import 'package:acela/src/models/hive_comments/new_hive_comment/newest_comment_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/login/ha_login_screen.dart'; +import 'package:acela/src/screens/video_details_screen/comment/comment_search_bar.dart'; +import 'package:acela/src/screens/video_details_screen/comment/comment_view_appbar.dart'; import 'package:acela/src/screens/video_details_screen/comment/controller/comment_controller.dart'; import 'package:acela/src/screens/video_details_screen/comment/hive_comment.dart'; import 'package:acela/src/screens/video_details_screen/comment/hive_comment_dialog.dart'; @@ -9,6 +11,7 @@ import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; class VideoDetailsComments extends StatefulWidget { const VideoDetailsComments({ @@ -30,46 +33,105 @@ class VideoDetailsComments extends StatefulWidget { } class _VideoDetailsCommentsState extends State { + final ValueNotifier showSearchBar = ValueNotifier(false); + final TextEditingController searchController = TextEditingController(); + final ItemScrollController itemScrollController = ItemScrollController(); + final ScrollOffsetController scrollOffsetController = + ScrollOffsetController(); + final ItemPositionsListener itemPositionsListener = + ItemPositionsListener.create(); + final ScrollOffsetListener scrollOffsetListener = + ScrollOffsetListener.create(); + late final CommentController controller; + @override void initState() { + controller = + CommentController(author: widget.author, permlink: widget.permlink); + _addListener(); super.initState(); } - Widget commentsListView(CommentController controller) { + void _addListener() { + showSearchBar.addListener(_searchBarListener); + } + + void _searchBarListener() async { + if (!showSearchBar.value) { + if (controller.animateToCommentIndex != null) { + await Future.delayed(Duration(milliseconds: 300)); + _animteToAddedComment(controller.animateToCommentIndex!); + controller.commentHighlighterTrigger = true; + } + } + } + + @override + void dispose() { + searchController.dispose(); + showSearchBar.removeListener(_searchBarListener); + super.dispose(); + } + + Widget commentsListView() { return Selector>( - shouldRebuild: (previous, next) => true, - selector: (_, myType) => myType.items, + shouldRebuild: (previous, next) => + previous != next || previous.length != next.length, + selector: (_, myType) => myType.disPlayedItems, builder: (context, items, child) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Expanded( - child: Container( - margin: const EdgeInsets.only(top: 10, bottom: 10), - child: ListView.separated( - itemBuilder: (context, index) { - final CommentItemModel item = items[index]; - return HiveCommentWidget( - key: ValueKey('${item.author}/${item.permlink}'), - comment: item,index: index,); - }, - separatorBuilder: (context, index) { - bool commentDividerVisibility = true; - commentDividerVisibility = _commentDividerVisibility( - index, items, commentDividerVisibility); - return Visibility( - visible: commentDividerVisibility, - child: const Divider( - height: 10, - color: Colors.blueGrey, + CommentSearchBar( + showSearchBar: showSearchBar, + onChanged: (value) { + controller.onSearch(value.trim()); + }, + textEditingController: searchController), + items.isNotEmpty + ? Expanded( + child: Container( + margin: const EdgeInsets.only(top: 10, bottom: 10), + child: ScrollablePositionedList.separated( + itemScrollController: itemScrollController, + scrollOffsetController: scrollOffsetController, + itemPositionsListener: itemPositionsListener, + scrollOffsetListener: scrollOffsetListener, + itemBuilder: (context, index) { + final CommentItemModel item = items[index]; + return CommentTile( + key: ValueKey( + '${item.author}/${item.permlink}/${item.created.toIso8601String()}'), + itemScrollController: itemScrollController, + isPadded: item.depth != 1 && + searchController.text.isEmpty, + currentUser: widget.appData.username!, + comment: item, + index: index, + searchKey: searchController.text.trim(), + ); + }, + separatorBuilder: (context, index) { + bool commentDividerVisibility = true; + commentDividerVisibility = _commentDividerVisibility( + index, items, commentDividerVisibility); + return Visibility( + visible: commentDividerVisibility, + child: const Divider( + height: 10, + color: Colors.blueGrey, + ), + ); + }, + itemCount: items.length, ), - ); - }, - itemCount: items.length, - ), - ), - ), - _addCommentButton(controller), + ), + ) + : Expanded( + child: Center( + child: Text("No Results Found"), + ), + ), ], ); }, @@ -88,32 +150,41 @@ class _VideoDetailsCommentsState extends State { return drawLine; } - Widget _addCommentButton(CommentController controller) { - return Padding( - padding: const EdgeInsets.only(left: 10.0, right: 10, bottom: 10), - child: SizedBox( - height: 35, - child: TextButton.icon( - style: TextButton.styleFrom( - padding: EdgeInsets.zero, - backgroundColor: Colors.blue, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(4), + Widget _addCommentButton() { + return Selector( + selector: (context, provider) => provider.viewState, + builder: (context, viewState, child) { + if (viewState == ViewState.data || viewState == ViewState.empty) { + return Padding( + padding: const EdgeInsets.only(left: 10.0, right: 10, bottom: 10), + child: SizedBox( + height: 35, + child: TextButton.icon( + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + backgroundColor: Colors.blue, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + ), + onPressed: () => commentPressed(controller), + icon: Icon( + Icons.add, + color: Colors.white, + ), + label: Text( + "Add a Comment", + style: TextStyle(color: Colors.white), + ), ), ), - ), - onPressed: () => commentPressed(controller), - icon: Icon( - Icons.add, - color: Colors.white, - ), - label: Text( - "Add a Comment", - style: TextStyle(color: Colors.white), - ), - ), - ), + ); + } else { + return SizedBox.shrink(); + } + }, ); } @@ -147,42 +218,54 @@ class _VideoDetailsCommentsState extends State { onClose: () {}, onDone: (newComment) async { if (newComment != null) { - controller.addTopLevelComment(newComment); + controller.addTopLevelComment( + newComment, searchController.text.trim()); + if (searchController.text.isEmpty) { + _animteToAddedComment(0); + } else if (controller.disPlayedItems.contains(newComment)) { + _animteToAddedComment(0); + } } }, ); Navigator.of(context).push(MaterialPageRoute(builder: (c) => screen)); } + void _animteToAddedComment(int index) { + itemScrollController.scrollTo( + index: index, + duration: Duration(milliseconds: 200), + curve: Curves.easeInOutCubic); + } + @override Widget build(BuildContext context) { - return ChangeNotifierProvider( - create: (context) => - CommentController(author: widget.author, permlink: widget.permlink), + return ChangeNotifierProvider.value( + value: controller, builder: (context, child) { - final controller = context.read(); return Selector( selector: (_, myType) => myType.viewState, builder: (context, state, child) { return Scaffold( - appBar: AppBar( - title: Selector( - selector: (_, myType) => myType.items.length, - builder: (context, numberOfComments, child) { - return Text( - 'Comments${state != ViewState.loading ? ' ($numberOfComments)' : ''}'); - }, - )), - body: _body(state, controller), + bottomNavigationBar: _addCommentButton(), + appBar: CommentViewAppbar( + state: state, + showSearchBar: showSearchBar, + ), + body: _body( + state, + ), ); }, ); }); } - Widget _body(ViewState state, CommentController controller) { + Widget _body( + ViewState state, + ) { if (state == ViewState.data) { - return commentsListView(controller); + return commentsListView(); } else if (state == ViewState.empty) { return Center( child: Text("No comments found"), diff --git a/pubspec.lock b/pubspec.lock index e84b9dfe..8ef1d200 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -958,26 +958,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.0" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "2.0.1" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "2.0.1" lints: dependency: transitive description: @@ -1030,10 +1030,10 @@ packages: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.11.0" mime: dependency: transitive description: @@ -1290,6 +1290,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.27.7" + scrollable_positioned_list: + dependency: "direct main" + description: + name: scrollable_positioned_list + sha256: "1b54d5f1329a1e263269abc9e2543d90806131aa14fe7c6062a8054d57249287" + url: "https://pub.dev" + source: hosted + version: "0.3.8" sentry: dependency: transitive description: @@ -1491,10 +1499,10 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.6.1" timeago: dependency: "direct main" description: @@ -1707,10 +1715,10 @@ packages: dependency: transitive description: name: vm_service - sha256: a2662fb1f114f4296cf3f5a50786a2d888268d7776cf681aa17d660ffa23b246 + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 url: "https://pub.dev" source: hosted - version: "14.0.0" + version: "13.0.0" wakelock: dependency: "direct main" description: @@ -1840,5 +1848,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.3.0-0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.2.3 <4.0.0" + flutter: ">=3.16.6" diff --git a/pubspec.yaml b/pubspec.yaml index 2d5f630e..af4b5581 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -94,6 +94,7 @@ dependencies: firebase_analytics: ^10.8.5 firebase_crashlytics: ^3.4.14 go_router: ^13.2.0 + scrollable_positioned_list: ^0.3.8 dev_dependencies: flutter_test: From f58ccb154875619e3927deb6db700fada8141aa5 Mon Sep 17 00:00:00 2001 From: sagar Date: Wed, 27 Mar 2024 16:12:01 +0530 Subject: [PATCH 390/466] comments section is fully done --- .../newest_comment_model.dart | 2 +- .../screens/my_account/my_account_screen.dart | 23 +-- .../comment/comment_view_appbar.dart | 30 ++-- .../controller/comment_controller.dart | 72 ++++++-- .../comment/hive_comment.dart | 63 +++++-- .../video_details_screen/comment/menu.dart | 52 ++++++ .../comment/video_details_comments.dart | 169 +++++++++++------- lib/src/utils/enum.dart | 2 + lib/src/widgets/confirmation_dialog.dart | 65 +++++++ 9 files changed, 346 insertions(+), 132 deletions(-) create mode 100644 lib/src/screens/video_details_screen/comment/menu.dart create mode 100644 lib/src/widgets/confirmation_dialog.dart diff --git a/lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart b/lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart index 3fecf375..0b6664b3 100644 --- a/lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart +++ b/lib/src/models/hive_comments/new_hive_comment/newest_comment_model.dart @@ -343,7 +343,7 @@ class CommentMetaDataModel { CommentMetaDataModel( tags: json["tags"] == null ? [] - : List.from(json["tags"]!.map((x) => x)), + : json['tags'] is String ? [json['tags']] : List.from(json["tags"]!.map((x) => x)), app: json["app"], ); diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index ddda55d1..f3c698b1 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -13,6 +13,7 @@ import 'package:acela/src/screens/video_details_screen/video_details_view_model. import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:acela/src/utils/routes/routes.dart'; +import 'package:acela/src/widgets/confirmation_dialog.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; @@ -115,24 +116,10 @@ class _MyAccountScreenState extends State showDialog( context: context, builder: (BuildContext context) { - return AlertDialog( - title: Text('Log Out'), - content: Text('Are you sure you want to log out?'), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text('No'), - ), - TextButton( - onPressed: () { - Navigator.of(context).pop(); - logout(widget.data); - }, - child: Text('Yes'), - ), - ], + return ConfirmationDialog( + title: 'Log Out', + content: 'Are you sure you want to log out?', + onConfirm: () => logout(widget.data), ); }, ); diff --git a/lib/src/screens/video_details_screen/comment/comment_view_appbar.dart b/lib/src/screens/video_details_screen/comment/comment_view_appbar.dart index 44e8803b..b01df849 100644 --- a/lib/src/screens/video_details_screen/comment/comment_view_appbar.dart +++ b/lib/src/screens/video_details_screen/comment/comment_view_appbar.dart @@ -1,25 +1,17 @@ import 'package:acela/src/screens/video_details_screen/comment/controller/comment_controller.dart'; +import 'package:acela/src/screens/video_details_screen/comment/menu.dart'; import 'package:acela/src/utils/enum.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -class CommentViewAppbar extends StatefulWidget implements PreferredSizeWidget { +class CommentViewAppbar extends StatelessWidget implements PreferredSizeWidget { const CommentViewAppbar( - {Key? key, required this.state, required this.showSearchBar}) + {Key? key, required this.state, required this.showSearchBar, required this.searchKey}) : super(key: key); final ViewState state; final ValueNotifier showSearchBar; - - @override - State createState() => _CommentViewAppbarState(); - - @override - Size get preferredSize => const Size.fromHeight(kToolbarHeight); -} - -class _CommentViewAppbarState extends State { - bool showSearch = false; + final TextEditingController searchKey; @override Widget build(BuildContext context) { @@ -27,10 +19,10 @@ class _CommentViewAppbarState extends State { .select((value) => value.disPlayedItems.length); return AppBar( title: Text( - 'Comments${widget.state != ViewState.loading ? ' ($numberOfComments)' : ''}'), + 'Comments${state != ViewState.loading ? ' ($numberOfComments)' : ''}'), actions: [ ValueListenableBuilder( - valueListenable: widget.showSearchBar, + valueListenable: showSearchBar, builder: (context, showSearchButton, child) { return Visibility( visible: numberOfComments != 0 && !showSearchButton, @@ -38,12 +30,18 @@ class _CommentViewAppbarState extends State { }, child: IconButton( onPressed: () { - widget.showSearchBar.value = true; + showSearchBar.value = true; }, icon: Icon(Icons.search), ), - ) + ), + Menu( + searchKey: searchKey, + ), ], ); } + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); } diff --git a/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart b/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart index 38044e22..8ed11fac 100644 --- a/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart +++ b/lib/src/screens/video_details_screen/comment/controller/comment_controller.dart @@ -10,6 +10,7 @@ class CommentController extends ChangeNotifier { ViewState viewState = ViewState.loading; List disPlayedItems = []; List items = []; + Sort sort = Sort.newest; bool _commentHighlighterTrigger = false; bool get commentHighlighterTrigger => _commentHighlighterTrigger; @@ -59,10 +60,17 @@ class CommentController extends ChangeNotifier { if (searchKey.isEmpty) { disPlayedItems = items; } else { - animateToCommentIndex = 0; if (_isSearchedKeyPresent(comment, searchKey)) { - disPlayedItems = [comment, ...disPlayedItems]; + if (sort == Sort.newest) { + disPlayedItems = [comment, ...disPlayedItems]; + } else { + disPlayedItems = [ + ...disPlayedItems, + comment, + ]; + } } + animateToCommentIndex = sort == Sort.newest ? 0 : items.length - 1; } notifyListeners(); } @@ -79,7 +87,14 @@ class CommentController extends ChangeNotifier { items = refactorComments(items, permlink); animateToCommentIndex = newIndex + 1; if (_isSearchedKeyPresent(comment, searchKey)) { - disPlayedItems = [comment, ...disPlayedItems]; + if (sort == Sort.newest) { + disPlayedItems = [comment, ...disPlayedItems]; + } else { + disPlayedItems = [ + ...disPlayedItems, + comment, + ]; + } } } } else { @@ -119,30 +134,38 @@ class CommentController extends ChangeNotifier { notifyListeners(); } - void refreshSilently() async { + void refresh() async { viewState = ViewState.loading; notifyListeners(); _init(); } - static List refactorComments( + void onSort(Sort sort, String searchKey) { + if (this.sort != sort) { + this.sort = sort; + if (searchKey.isEmpty) { + disPlayedItems = [...refactorComments(disPlayedItems, permlink)]; + items = [...disPlayedItems]; + } else { + if (animateToCommentIndex != null) { + animateToCommentIndex = null; + } + items = [...refactorComments(items, permlink)]; + _sortList(disPlayedItems); + disPlayedItems = [...disPlayedItems]; + } + notifyListeners(); + } + } + + List refactorComments( List content, String parentPermlink) { List refactoredComments = []; var newContent = List.from(content); for (var e in newContent) { e.visited = false; } - newContent.sort((a, b) { - var bTime = b.created; - var aTime = a.created; - if (aTime.isAfter(bTime)) { - return -1; - } else if (bTime.isAfter(aTime)) { - return 1; - } else { - return 0; - } - }); + _sortList(newContent); refactoredComments.addAll( newContent.where((e) => e.parentPermlink == parentPermlink).toList()); while (refactoredComments.where((e) => e.visited == false).isNotEmpty) { @@ -180,14 +203,31 @@ class CommentController extends ChangeNotifier { data.add(item); } } + disPlayedItems = data.toList(); + _sortList(disPlayedItems); notifyListeners(); } else { disPlayedItems = items; + disPlayedItems = refactorComments(disPlayedItems, permlink); notifyListeners(); } } + void _sortList(List list) { + list.sort((a, b) { + var bTime = sort == Sort.newest ? b.created : a.created; + var aTime = sort == Sort.newest ? a.created : b.created; + if (aTime.isAfter(bTime)) { + return -1; + } else if (bTime.isAfter(aTime)) { + return 1; + } else { + return 0; + } + }); + } + bool _isSearchedKeyPresent(CommentItemModel item, String keyword) { if (item.body.toLowerCase().contains(keyword.toLowerCase())) { return true; diff --git a/lib/src/screens/video_details_screen/comment/hive_comment.dart b/lib/src/screens/video_details_screen/comment/hive_comment.dart index 9c1659d7..e5d57cc5 100644 --- a/lib/src/screens/video_details_screen/comment/hive_comment.dart +++ b/lib/src/screens/video_details_screen/comment/hive_comment.dart @@ -2,7 +2,9 @@ import 'package:acela/src/models/hive_comments/new_hive_comment/newest_comment_m import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/video_details_screen/comment/comment_action_menu.dart'; import 'package:acela/src/screens/video_details_screen/comment/controller/comment_controller.dart'; +import 'package:acela/src/utils/enum.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; +import 'package:acela/src/widgets/confirmation_dialog.dart'; import 'package:acela/src/widgets/user_profile_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; @@ -39,13 +41,16 @@ class _CommentTileState extends State late bool isUpvoted; bool animate = false; bool animated = false; - Duration duration = Duration(seconds: 5); + Duration duration = Duration.zero; + late bool isHidden; late Color color; @override void initState() { _initVoteStatus(); _initAnimation(); + isHidden = (widget.comment.authorReputation ?? 0) < 0 || + (widget.comment.netRshares ?? 0) < 0; super.initState(); } @@ -58,6 +63,7 @@ class _CommentTileState extends State WidgetsBinding.instance.addPostFrameCallback((timeStamp) { if (mounted) setState(() { + duration = Duration(seconds: 5); color = Colors.transparent; animated = true; animate = false; @@ -123,20 +129,27 @@ class _CommentTileState extends State }, child: InkWell( onTap: () { - if (!widget.comment.isLocallyAdded) { - _showBottomSheet(item, onUpvote: () { - context.read().onUpvote( - item, widget.index, widget.currentUser, widget.searchKey); - setState(() { - votes++; - isUpvoted = true; + if (isHidden) { + _showCommentUnMuteDialog(); + } else { + if (!widget.comment.isLocallyAdded) { + _showBottomSheet(item, onUpvote: () { + context.read().onUpvote( + item, widget.index, widget.currentUser, widget.searchKey); + setState(() { + votes++; + isUpvoted = true; + }); }); - }); + } } }, child: AnimatedContainer( duration: duration, color: color, + onEnd: () => setState(() { + duration = Duration.zero; + }), padding: EdgeInsets.only( left: depth + 15, right: 15, @@ -182,7 +195,12 @@ class _CommentTileState extends State style: style, overflow: TextOverflow.ellipsis, maxLines: 1, - )), + ),), + if (isHidden) + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Icon(Icons.visibility_off), + ) ], ), ) @@ -191,7 +209,7 @@ class _CommentTileState extends State const SizedBox( height: 8, ), - _comment(body), + if (!isHidden) _comment(body) ], ), ), @@ -227,7 +245,9 @@ class _CommentTileState extends State if (widget.searchKey.isNotEmpty && controller.disPlayedItems.contains(newComment)) { - _animteToAddedComment(0); + _animteToAddedComment(controller.sort == Sort.newest + ? 0 + : controller.disPlayedItems.length - 1); } }, onUpVote: onUpvote, @@ -238,6 +258,25 @@ class _CommentTileState extends State ); } + void _showCommentUnMuteDialog() { + showDialog( + barrierDismissible: true, + useRootNavigator: true, + context: context, + builder: (context) { + return ConfirmationDialog( + title: "Muted comment", + content: "Are you sure you want to see muted comment ?", + onConfirm: () { + if (mounted) + setState(() { + isHidden = false; + }); + }); + }, + ); + } + void _animteToAddedComment(int index) { widget.itemScrollController.scrollTo( index: index, diff --git a/lib/src/screens/video_details_screen/comment/menu.dart b/lib/src/screens/video_details_screen/comment/menu.dart new file mode 100644 index 00000000..3d17a4c5 --- /dev/null +++ b/lib/src/screens/video_details_screen/comment/menu.dart @@ -0,0 +1,52 @@ +import 'package:acela/src/screens/video_details_screen/comment/controller/comment_controller.dart'; +import 'package:acela/src/utils/enum.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class Menu extends StatelessWidget { + const Menu({ + Key? key, + required this.searchKey, + }) : super( + key: key, + ); + + final TextEditingController searchKey; + + @override + Widget build(BuildContext context) { + final controller = context.read(); + return PopupMenuButton( + constraints: BoxConstraints(), + padding: EdgeInsets.zero, + tooltip: "Sort", + icon: Icon( + Icons.filter_list, + ), + itemBuilder: (context) { + return [ + PopupMenuItem( + height: 40, + padding: const EdgeInsets.only(left: 10), + onTap: () => controller.onSort(Sort.newest, searchKey.text.trim()), + child: Text( + 'Newest', + style: TextStyle( + color: controller.sort == Sort.newest ? Colors.blue : null), + ), + ), + PopupMenuItem( + height: 40, + padding: const EdgeInsets.only(left: 10), + onTap: () => controller.onSort(Sort.oldest, searchKey.text.trim()), + child: Text( + 'Oldest', + style: TextStyle( + color: controller.sort == Sort.oldest ? Colors.blue : null), + ), + ) + ]; + }, + ); + } +} diff --git a/lib/src/screens/video_details_screen/comment/video_details_comments.dart b/lib/src/screens/video_details_screen/comment/video_details_comments.dart index f43e1d67..e9fd4403 100644 --- a/lib/src/screens/video_details_screen/comment/video_details_comments.dart +++ b/lib/src/screens/video_details_screen/comment/video_details_comments.dart @@ -92,39 +92,16 @@ class _VideoDetailsCommentsState extends State { ? Expanded( child: Container( margin: const EdgeInsets.only(top: 10, bottom: 10), - child: ScrollablePositionedList.separated( - itemScrollController: itemScrollController, - scrollOffsetController: scrollOffsetController, - itemPositionsListener: itemPositionsListener, - scrollOffsetListener: scrollOffsetListener, - itemBuilder: (context, index) { - final CommentItemModel item = items[index]; - return CommentTile( - key: ValueKey( - '${item.author}/${item.permlink}/${item.created.toIso8601String()}'), - itemScrollController: itemScrollController, - isPadded: item.depth != 1 && - searchController.text.isEmpty, - currentUser: widget.appData.username!, - comment: item, - index: index, - searchKey: searchController.text.trim(), - ); - }, - separatorBuilder: (context, index) { - bool commentDividerVisibility = true; - commentDividerVisibility = _commentDividerVisibility( - index, items, commentDividerVisibility); - return Visibility( - visible: commentDividerVisibility, - child: const Divider( - height: 10, - color: Colors.blueGrey, - ), - ); - }, - itemCount: items.length, - ), + child: searchController.text.trim().isEmpty + ? RefreshIndicator( + onRefresh: () async { + if (searchController.text.trim().isEmpty) { + controller.refresh(); + } + }, + child: _commentListViewBuilder(items), + ) + : _commentListViewBuilder(items), ), ) : Expanded( @@ -138,6 +115,42 @@ class _VideoDetailsCommentsState extends State { ); } + ScrollablePositionedList _commentListViewBuilder( + List items) { + return ScrollablePositionedList.separated( + itemScrollController: itemScrollController, + scrollOffsetController: scrollOffsetController, + itemPositionsListener: itemPositionsListener, + scrollOffsetListener: scrollOffsetListener, + itemBuilder: (context, index) { + final CommentItemModel item = items[index]; + return CommentTile( + key: ValueKey( + '${item.author}/${item.permlink}/${item.created.toIso8601String()}'), + itemScrollController: itemScrollController, + isPadded: item.depth != 1 && searchController.text.isEmpty, + currentUser: widget.appData.username!, + comment: item, + index: index, + searchKey: searchController.text.trim(), + ); + }, + separatorBuilder: (context, index) { + bool commentDividerVisibility = true; + commentDividerVisibility = + _commentDividerVisibility(index, items, commentDividerVisibility); + return Visibility( + visible: commentDividerVisibility, + child: const Divider( + height: 10, + color: Colors.blueGrey, + ), + ); + }, + itemCount: items.length, + ); + } + bool _commentDividerVisibility( int index, List items, bool drawLine) { if (index + 1 < items.length) { @@ -151,40 +164,42 @@ class _VideoDetailsCommentsState extends State { } Widget _addCommentButton() { - return Selector( - selector: (context, provider) => provider.viewState, - builder: (context, viewState, child) { - if (viewState == ViewState.data || viewState == ViewState.empty) { - return Padding( - padding: const EdgeInsets.only(left: 10.0, right: 10, bottom: 10), - child: SizedBox( - height: 35, - child: TextButton.icon( - style: TextButton.styleFrom( - padding: EdgeInsets.zero, - backgroundColor: Colors.blue, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(4), + return SafeArea( + child: Selector( + selector: (context, provider) => provider.viewState, + builder: (context, viewState, child) { + if (viewState == ViewState.data || viewState == ViewState.empty) { + return Padding( + padding: const EdgeInsets.only(left: 10.0, right: 10, bottom: 10), + child: SizedBox( + height: 35, + child: TextButton.icon( + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + backgroundColor: Colors.blue, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(4), + ), ), ), - ), - onPressed: () => commentPressed(controller), - icon: Icon( - Icons.add, - color: Colors.white, - ), - label: Text( - "Add a Comment", - style: TextStyle(color: Colors.white), + onPressed: () => commentPressed(controller), + icon: Icon( + Icons.add, + color: Colors.white, + ), + label: Text( + "Add a Comment", + style: TextStyle(color: Colors.white), + ), ), ), - ), - ); - } else { - return SizedBox.shrink(); - } - }, + ); + } else { + return SizedBox.shrink(); + } + }, + ), ); } @@ -220,10 +235,13 @@ class _VideoDetailsCommentsState extends State { if (newComment != null) { controller.addTopLevelComment( newComment, searchController.text.trim()); + int animateToindex = controller.sort == Sort.newest + ? 0 + : controller.disPlayedItems.length - 1; if (searchController.text.isEmpty) { - _animteToAddedComment(0); + _animteToAddedComment(animateToindex); } else if (controller.disPlayedItems.contains(newComment)) { - _animteToAddedComment(0); + _animteToAddedComment(animateToindex); } } }, @@ -250,10 +268,13 @@ class _VideoDetailsCommentsState extends State { bottomNavigationBar: _addCommentButton(), appBar: CommentViewAppbar( state: state, + searchKey: searchController, showSearchBar: showSearchBar, ), - body: _body( - state, + body: SafeArea( + child: _body( + state, + ), ), ); }, @@ -272,8 +293,18 @@ class _VideoDetailsCommentsState extends State { ); } else if (state == ViewState.error) { return Container( - margin: const EdgeInsets.all(10), - child: Text("Sorry, something went wrong")); + margin: const EdgeInsets.all(10), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("Sorry, something went wrong"), + TextButton( + onPressed: () => controller.refresh(), child: Text("Retry")) + ], + ), + ), + ); } else { return Center( child: Column( diff --git a/lib/src/utils/enum.dart b/lib/src/utils/enum.dart index 46566e1d..76cc666b 100644 --- a/lib/src/utils/enum.dart +++ b/lib/src/utils/enum.dart @@ -1,3 +1,5 @@ enum ViewState{loading,data,empty,error} enum UploadStatus { idle, started, ended } + +enum Sort {newest,oldest} diff --git a/lib/src/widgets/confirmation_dialog.dart b/lib/src/widgets/confirmation_dialog.dart new file mode 100644 index 00000000..78d9958c --- /dev/null +++ b/lib/src/widgets/confirmation_dialog.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; + +class ConfirmationDialog extends StatelessWidget { + const ConfirmationDialog({ + required this.title, + required this.content, + required this.onConfirm, + }); + + final String title; + final String content; + final VoidCallback onConfirm; + + @override + Widget build(BuildContext context) { + return AlertDialog( + actionsPadding: const EdgeInsets.only(bottom: 20, right: 20), + title: Text( + title, + ), + content: Text( + content, + ), + actions: [ + DialogButton( + text: "No", + onPressed: () { + Navigator.pop(context); + }), + DialogButton( + text: "Yes", + onPressed: () { + Navigator.pop(context); + onConfirm(); + }, + ), + ], + ); + } +} + +class DialogButton extends StatelessWidget { + const DialogButton({ + required this.text, + required this.onPressed, + }); + + final String text; + final Function() onPressed; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 25, + child: TextButton( + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + backgroundColor: Theme.of(context).primaryColor), + onPressed: onPressed, + child: Text( + text, + )), + ); + } +} From a6c706ffa582deddd6e19428b755da9898b034f2 Mon Sep 17 00:00:00 2001 From: sagar Date: Wed, 27 Mar 2024 18:18:14 +0530 Subject: [PATCH 391/466] video upload improvements- removed default tags in textfield,bene improvements --- .../update_video/add_bene_sheet.dart | 151 +++++++++++------- .../controller/video_upload_controller.dart | 1 - .../upload/video/video_upload_screen.dart | 2 +- .../video/widgets/beneficaries_tile.dart | 53 +++++- lib/src/widgets/user_profile_image.dart | 27 ++-- 5 files changed, 158 insertions(+), 76 deletions(-) diff --git a/lib/src/screens/my_account/update_video/add_bene_sheet.dart b/lib/src/screens/my_account/update_video/add_bene_sheet.dart index 488d6900..37d690e3 100644 --- a/lib/src/screens/my_account/update_video/add_bene_sheet.dart +++ b/lib/src/screens/my_account/update_video/add_bene_sheet.dart @@ -1,6 +1,10 @@ +import 'dart:developer'; + import 'package:acela/src/models/my_account/video_ops.dart'; -import 'package:flutter/material.dart'; +import 'package:acela/src/widgets/user_profile_image.dart'; import 'package:collection/collection.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; class AddBeneSheet extends StatefulWidget { const AddBeneSheet({ @@ -20,23 +24,43 @@ class _AddBeneSheetState extends State { var name = ''; var _controller = TextEditingController(); + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + Widget _beneNameField() { return Container( margin: const EdgeInsets.only(left: 10, right: 10), - child: TextField( - controller: _controller, - decoration: const InputDecoration( - hintText: 'Video Participant Hive Account Name', - labelText: 'Account Name', - ), - onChanged: (text) { - setState(() { - name = text; - }); - }, - maxLines: 1, - minLines: 1, - maxLength: 150, + child: Row( + children: [ + ValueListenableBuilder( + valueListenable: _controller, + builder: (context, value, child) { + return UserProfileImage(userName: _controller.text); + }), + const SizedBox( + width: 10, + ), + Expanded( + child: TextField( + controller: _controller, + decoration: InputDecoration( + hintText: 'Video Participant Hive Account Name', + labelText: 'Account Name', + ), + onChanged: (text) { + setState(() { + name = text; + }); + }, + maxLines: 1, + minLines: 1, + maxLength: 150, + ), + ), + ], ), ); } @@ -53,55 +77,64 @@ class _AddBeneSheetState extends State { @override Widget build(BuildContext context) { + log(MediaQuery.of(context).viewInsets.bottom.toString()); var author = widget.benes.where((element) => element.src == 'author').firstOrNull; var max = ((author?.weight ?? 99) - 1) * 100; return SafeArea( - child: Scaffold( - appBar: AppBar( - title: Text('Add Participant'), - actions: [ - IconButton( - onPressed: () { - if (author == null) return; - if (name.isEmpty) return; - var names = - widget.benes.map((e) => e.account.toLowerCase()).toList(); - var participant = name.toLowerCase().trim(); - if (names.contains(participant)) { - showError('Video Participant already added'); - } else { - var percentValue = newBeneValue ~/ 100; - var newList = widget.benes; - newList.add( - BeneficiariesJson( - account: participant, - weight: percentValue, - src: 'participant', - ), - ); - newList = newList.where((e) => e.src != 'author').toList(); - var sum = newList.map((e) => e.weight).toList().sum; - var newWeight = 100 - sum; - newList.add( - BeneficiariesJson( - account: author.account, weight: newWeight, src: 'author'), - ); - widget.onSave(newList); - Navigator.of(context).pop(); - } - }, - icon: Icon(Icons.add), - ) - ], - ), - body: SafeArea( - child: (author == null) + child: Container( + color: Theme.of(context).scaffoldBackgroundColor, + height: 400, + margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + child: Column( + children: [ + AppBar( + title: Text('Add Participant'), + actions: [ + IconButton( + onPressed: () { + if (author == null) return; + if (name.isEmpty) return; + var names = + widget.benes.map((e) => e.account.toLowerCase()).toList(); + var participant = name.toLowerCase().trim(); + if (names.contains(participant)) { + showError('Video Participant already added'); + } else { + var percentValue = newBeneValue ~/ 100; + var newList = widget.benes; + newList.add( + BeneficiariesJson( + account: participant, + weight: percentValue, + src: 'participant', + ), + ); + newList = newList.where((e) => e.src != 'author').toList(); + var sum = newList.map((e) => e.weight).toList().sum; + var newWeight = 100 - sum; + newList.add( + BeneficiariesJson( + account: author.account, + weight: newWeight, + src: 'author'), + ); + widget.onSave(newList); + Navigator.of(context).pop(); + } + }, + icon: Icon(Icons.add), + ) + ], + ), + (author == null) ? Container() - : SingleChildScrollView( - child: Column( + : Expanded( + child: ListView( + // mainAxisSize: MainAxisSize.min, children: [ _beneNameField(), + const SizedBox(height: 15,), Slider( value: newBeneValue.toDouble(), min: 100.0, @@ -121,8 +154,8 @@ class _AddBeneSheetState extends State { ], ), ), - ), + ], ), - ); + )); } } diff --git a/lib/src/screens/upload/video/controller/video_upload_controller.dart b/lib/src/screens/upload/video/controller/video_upload_controller.dart index 225455f3..94335947 100644 --- a/lib/src/screens/upload/video/controller/video_upload_controller.dart +++ b/lib/src/screens/upload/video/controller/video_upload_controller.dart @@ -20,7 +20,6 @@ class VideoUploadController extends ChangeNotifier with Upload, VideoSaveMixin { VideoUploadController() { setCommunity(); - setTags(); setLanguage(); } diff --git a/lib/src/screens/upload/video/video_upload_screen.dart b/lib/src/screens/upload/video/video_upload_screen.dart index 89691264..3e8d9969 100644 --- a/lib/src/screens/upload/video/video_upload_screen.dart +++ b/lib/src/screens/upload/video/video_upload_screen.dart @@ -108,7 +108,7 @@ class _VideoUploadScreenState extends State { ), UploadTextField( textEditingController: tagsController, - hintText: 'Comma separated tags', + hintText: 'threespeak,mobile', labelText: 'Tags', maxLines: 1, minLines: 1, diff --git a/lib/src/screens/upload/video/widgets/beneficaries_tile.dart b/lib/src/screens/upload/video/widgets/beneficaries_tile.dart index c75ed34d..f5c683ad 100644 --- a/lib/src/screens/upload/video/widgets/beneficaries_tile.dart +++ b/lib/src/screens/upload/video/widgets/beneficaries_tile.dart @@ -2,6 +2,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/my_account/video_ops.dart'; import 'package:acela/src/screens/my_account/update_video/add_bene_sheet.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; +import 'package:acela/src/widgets/user_profile_image.dart'; import 'package:flutter/material.dart'; class BeneficiariesTile extends StatefulWidget { @@ -31,15 +32,59 @@ class _BeneficiariesTileState extends State { @override Widget build(BuildContext context) { + final theme = Theme.of(context); return InkWell( onTap: () { beneficiariesBottomSheet(context); }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + Text('Video Participants:'), + Spacer(), + Icon(Icons.arrow_drop_down), + ], + ), + Visibility( + visible: beneficiaries.isNotEmpty, + child: Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Wrap( + spacing: 10, + runSpacing: 10, + children: List.generate( + beneficiaries.length, + (index) => _beneficarieNameTile(theme, index, context), + ), + )), + ) + ], + ), + ); + } + + Container _beneficarieNameTile( + ThemeData theme, int index, BuildContext context) { + return Container( + padding: EdgeInsets.only(top: 2, bottom: 2, right: 8, left: 3), + decoration: BoxDecoration( + color: theme.cardColor, + borderRadius: BorderRadius.all(Radius.circular(20))), child: Row( + mainAxisSize: MainAxisSize.min, children: [ - Text('Video Participants:'), - Spacer(), - Icon(Icons.arrow_drop_down), + UserProfileImage(radius: 20, userName: beneficiaries[index].account), + const SizedBox( + width: 5, + ), + Text( + beneficiaries[index].account, + style: TextStyle( + color: Theme.of(context).primaryColorLight.withOpacity(0.7), + ), + ), ], ), ); @@ -124,6 +169,8 @@ class _BeneficiariesTileState extends State { void showAlertForAddBene(List benes) { showModalBottomSheet( context: context, + isScrollControlled: true, + useSafeArea: true, builder: (context) { return AddBeneSheet( benes: benes, diff --git a/lib/src/widgets/user_profile_image.dart b/lib/src/widgets/user_profile_image.dart index 6c5a8c62..bfda8169 100644 --- a/lib/src/widgets/user_profile_image.dart +++ b/lib/src/widgets/user_profile_image.dart @@ -2,25 +2,28 @@ import 'package:acela/src/bloc/server.dart'; import 'package:flutter/material.dart'; class UserProfileImage extends StatelessWidget { - const UserProfileImage({Key? key, required this.userName}) : super(key: key); + const UserProfileImage({Key? key, required this.userName, this.radius}) + : super(key: key); final String userName; + final double? radius; @override Widget build(BuildContext context) { return Container( - height: 40, - width: 40, + height: radius ?? 40, + width: radius ?? 40, decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.grey.shade800, - image: DecorationImage( - fit: BoxFit.cover, - image: NetworkImage( - server.userOwnerThumb(userName), - ), - ), - ), + shape: BoxShape.circle, + color: Colors.grey.shade800, + image: userName.isNotEmpty + ? DecorationImage( + fit: BoxFit.cover, + image: NetworkImage( + server.userOwnerThumb(userName), + ), + ) + : null), ); } } From 3edd85aec64a16572c0849c9284ec2c58a173ec7 Mon Sep 17 00:00:00 2001 From: sagar Date: Thu, 28 Mar 2024 20:16:50 +0530 Subject: [PATCH 392/466] video upload,account screen,podcast improvements --- .../video_details_model/video_details.dart | 13 +- .../screens/home_screen/new_home_screen.dart | 13 +- .../screens/my_account/my_account_screen.dart | 239 +++++++++++------- .../podcast/view/local_podcast_episode.dart | 118 +++++---- lib/src/screens/search/search_screen.dart | 19 +- .../upload/video/video_upload_screen.dart | 35 ++- .../video/widgets/beneficaries_tile.dart | 52 ++-- .../video/widgets/community_picker.dart | 98 ++++--- .../upload/video/widgets/language_tile.dart | 3 +- .../video/widgets/reward_type_widget.dart | 32 ++- .../video/widgets/thumbnail_picker.dart | 116 ++++++--- .../widgets/uploadProgressExpansionTile.dart | 106 ++++---- .../video/widgets/upload_textfield.dart | 32 ++- .../video/widgets/video_upload_divider.dart | 12 + .../video/widgets/work_type_widget.dart | 43 ++-- lib/src/utils/constants.dart | 5 + lib/src/utils/graphql/gql_communicator.dart | 1 - 17 files changed, 574 insertions(+), 363 deletions(-) create mode 100644 lib/src/screens/upload/video/widgets/video_upload_divider.dart create mode 100644 lib/src/utils/constants.dart diff --git a/lib/src/models/video_details_model/video_details.dart b/lib/src/models/video_details_model/video_details.dart index c0fbe80d..4e81755e 100644 --- a/lib/src/models/video_details_model/video_details.dart +++ b/lib/src/models/video_details_model/video_details.dart @@ -25,7 +25,7 @@ class VideoDetails { final String status; final String playUrl; final String language; - + final int? encodingProgress; final String thumbnail; final String video_v2; @@ -41,8 +41,7 @@ class VideoDetails { final String visible_status; String getThumbnail() { - return thumbnail.replaceAll( - 'ipfs://', IpfsNodeProvider().nodeUrl); + return thumbnail.replaceAll('ipfs://', IpfsNodeProvider().nodeUrl); } String getVideoUrl(HiveUserData data) { @@ -65,8 +64,7 @@ class VideoDetails { // https://ipfs-3speak.b-cdn.net/ipfs/QmTRDJcgtt66pxs3ZnQCdRw57b69NS2TQvF4yHwaux5grT/manifest.m3u8 // https://ipfs-3speak.b-cdn.net/ipfs/QmTRDJcgtt66pxs3ZnQCdRw57b69NS2TQvF4yHwaux5grT/480p/index.m3u8 // https://ipfs-3speak.b-cdn.net/ipfs/QmWADpD1PWPnmYVkSZvgokU5vcN2qZqvsHCA985GZ5Jf4r/manifest.m3u8 - var url = - video_v2.replaceAll('ipfs://', IpfsNodeProvider().nodeUrl); + var url = video_v2.replaceAll('ipfs://', IpfsNodeProvider().nodeUrl); log('Root Play url is - $url'); return url; } @@ -120,6 +118,7 @@ class VideoDetails { this.playUrl = "", this.steemPosted = false, this.status = "", + required this.encodingProgress, required this.video_v2, required this.tags, required this.originalFilename, @@ -179,8 +178,7 @@ class VideoDetails { if (sum < 100) { var remaining = 100 - sum; beneficiariesToSet.add( - BeneficiariesJson( - account: owner, src: 'author', weight: remaining), + BeneficiariesJson(account: owner, src: 'author', weight: remaining), ); } return beneficiariesToSet; @@ -204,6 +202,7 @@ class VideoDetails { views: asInt(json, 'views'), tagsV2: asList(json, 'tags_v2').map((e) => e.toString()).toList(), id: asString(json, '_id'), + encodingProgress: json!=null ? asInt(json, 'encodingProgress') : null, community: asString(json, 'community'), permlink: asString(json, 'permlink'), duration: asDouble(json, 'duration'), diff --git a/lib/src/screens/home_screen/new_home_screen.dart b/lib/src/screens/home_screen/new_home_screen.dart index d322afde..067db68d 100644 --- a/lib/src/screens/home_screen/new_home_screen.dart +++ b/lib/src/screens/home_screen/new_home_screen.dart @@ -5,9 +5,6 @@ import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/bott import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/tab_title_toast.dart'; import 'package:acela/src/screens/home_screen/home_screen_feed_list.dart'; import 'package:acela/src/screens/login/ha_login_screen.dart'; -import 'package:acela/src/screens/podcast/view/podcast_trending.dart'; -import 'package:acela/src/screens/search/search_screen.dart'; -import 'package:acela/src/screens/stories/new_tab_based_stories.dart'; import 'package:acela/src/screens/trending_tags/trending_tags.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -60,20 +57,30 @@ class _GQLFeedScreenState extends State super.initState(); _tabController = TabController(vsync: this, length: widget.username != null ? 6 : 5); + _tabController.addListener(tabBarListener); } @override void didUpdateWidget(covariant GQLFeedScreen oldWidget) { if (widget.username != oldWidget.username) { + _tabController.removeListener(tabBarListener); _tabController.dispose(); _tabController = TabController(vsync: this, length: widget.username != null ? 6 : 5); + _tabController.addListener(tabBarListener); } super.didUpdateWidget(oldWidget); } + void tabBarListener() { + setState(() { + currentIndex = _tabController.index; + }); + } + @override void dispose() { + _tabController.removeListener(tabBarListener); _tabController.dispose(); super.dispose(); } diff --git a/lib/src/screens/my_account/my_account_screen.dart b/lib/src/screens/my_account/my_account_screen.dart index f3c698b1..3081b8fc 100644 --- a/lib/src/screens/my_account/my_account_screen.dart +++ b/lib/src/screens/my_account/my_account_screen.dart @@ -25,8 +25,10 @@ class MyAccountScreen extends StatefulWidget { const MyAccountScreen({ Key? key, required this.data, + this.initialTabIndex, }) : super(key: key); final HiveUserData data; + final int? initialTabIndex; @override State createState() => _MyAccountScreenState(); @@ -44,7 +46,8 @@ class _MyAccountScreenState extends State setState(() { loadVideos = Communicator().loadVideos(widget.data); }); - _tabController = TabController(length: 3, vsync: this); + _tabController = TabController( + length: 3, vsync: this, initialIndex: widget.initialTabIndex ?? 0); _tabController.addListener(() { setState(() { currentIndex = _tabController.index; @@ -89,7 +92,8 @@ class _MyAccountScreenState extends State tabs: [ Tab(icon: Text('Publish Now')), Tab(icon: Text('My Videos')), - Tab(icon: Text('Others')), + Tab(icon: Text('Encoding')), + // Tab(icon: Text('Deleted')), ], ), actions: [ @@ -131,68 +135,105 @@ class _MyAccountScreenState extends State } Widget _trailingActionOnVideoListItem(VideoDetails item, HiveUserData user) { - return item.status == 'published' - ? const Icon( - Icons.more_vert, - ) - : item.status == "encoding_failed" || - item.status.toLowerCase() == "deleted" - ? const Icon(Icons.cancel_outlined, color: Colors.red) - : item.status == 'publish_manual' - ? Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - height: 25, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.all(Radius.circular(4))), - padding: EdgeInsets.symmetric( - horizontal: 2, vertical: 0)), - onPressed: () { - var screen = VideoPrimaryInfo( - item: item, justForEditing: false); - var route = - MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - child: Text('Publish'), - ), - ), - const SizedBox( - width: 5, - ), - SizedBox( - height: 25, - width: 25, - child: Center( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.all(Radius.circular(4))), - padding: EdgeInsets.zero), - onPressed: () { - _showBottomSheet(item); - }, - child: Center( - child: Icon(Icons.more_vert), - ), - ), - ), - ), - ], + if (item.status == 'published') { + return const Icon( + Icons.more_vert, + ); + } else if (item.status == "encoding_failed" || + item.status.toLowerCase() == "deleted") { + return const Icon(Icons.cancel_outlined, color: Colors.red); + } else if (item.status == 'publish_manual') { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 25, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4))), + padding: EdgeInsets.symmetric(horizontal: 2, vertical: 0)), + onPressed: () { + var screen = + VideoPrimaryInfo(item: item, justForEditing: false); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + child: Text('Publish'), + ), + ), + const SizedBox( + width: 5, + ), + SizedBox( + height: 25, + width: 25, + child: Center( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4))), + padding: EdgeInsets.zero), + onPressed: () { + _showBottomSheet(item); + }, + child: Center( + child: Icon(Icons.more_vert), + ), + ), + ), + ), + ], + ); + } else { + bool isEncodingFailed = isEncodedFailed(item.created); + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + isEncodingFailed + ? Icon( + Icons.block, + color: Colors.red, + ) + : Icon( + Icons.hourglass_top, + color: Colors.yellowAccent, + ), + if (item.encodingProgress != null) + isEncodingFailed + ? Text( + "Failed", + style: TextStyle(color: Colors.red), ) - : const Icon( - Icons.hourglass_top, - color: Colors.yellowAccent, - ); + : Text("${item.encodingProgress.toString()}%") + ], + ); + } + } + + bool isEncodedFailed(String dateString) { + DateTime parsedDate = DateTime.parse(dateString); + DateTime currentDate = DateTime.now(); + Duration difference = currentDate.difference(parsedDate); + if (difference.inDays > 30) { + return true; + } else { + return false; + } } void _showBottomSheet(VideoDetails item) { - var actions = [ + List actions = []; + if (currentIndex == 0) { + actions.add(BottomSheetAction( + title: const Text("Publish"), + onPressed: (context) { + var screen = VideoPrimaryInfo(item: item, justForEditing: false); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + })); + } + actions.add( BottomSheetAction( title: const Text('Change Thumbnail'), onPressed: (context) { @@ -202,7 +243,7 @@ class _MyAccountScreenState extends State Navigator.of(context).push(route); }, ), - ]; + ); if (item.status == 'published') { actions.add( BottomSheetAction( @@ -217,26 +258,8 @@ class _MyAccountScreenState extends State }, ), ); - actions.add( - BottomSheetAction( - title: Text('Delete Video'), - onPressed: (context) async { - Navigator.of(context).pop(); - showSnackBar('Deleting...', seconds: 60); - bool result = - await Communicator().deleteVideo(item.permlink, widget.data); - hideSnackBar(); - if (result) { - setState(() { - loadVideos = Communicator().loadVideos(widget.data); - }); - } else { - showSnackBar("Something went wrong"); - } - }, - ), - ); } + if (item.status == 'publish_manual') { actions.add(BottomSheetAction( title: Text('Preview'), @@ -248,6 +271,28 @@ class _MyAccountScreenState extends State }, )); } + actions.add( + BottomSheetAction( + title: Text( + 'Delete Video', + style: TextStyle(color: Colors.red), + ), + onPressed: (context) async { + Navigator.of(context).pop(); + showSnackBar('Deleting...', seconds: 60); + bool result = + await Communicator().deleteVideo(item.permlink, widget.data); + hideSnackBar(); + if (result) { + setState(() { + loadVideos = Communicator().loadVideos(widget.data); + }); + } else { + showSnackBar("Something went wrong"); + } + }, + ), + ); // if (item.status == 'publish_manual') { // actions.add(BottomSheetAction( // title: Text( @@ -302,7 +347,9 @@ class _MyAccountScreenState extends State subtitle: Text(desc), trailing: _trailingActionOnVideoListItem(item, user), onTap: () { - if (item.status != 'publish_manual' && + if (currentIndex == 0) { + _showBottomSheet(item); + } else if (item.status != 'publish_manual' && item.status != 'encoding_failed' && item.status.toLowerCase() != 'deleted') { _showBottomSheet(item); @@ -314,7 +361,7 @@ class _MyAccountScreenState extends State Widget _listViewForItems(List items, HiveUserData user) { if (items.isEmpty) { return const Center( - child: Text('No Items found.'), + child: Text('No videos found.'), ); } return RefreshIndicator( @@ -326,16 +373,11 @@ class _MyAccountScreenState extends State child: ListView.separated( itemBuilder: (context, index) { if (index == 0) { - var text = currentIndex == 0 - ? 'Your videos are ready to post\nTap on a video to edit details & publish' - : currentIndex == 1 - ? 'Following videos are already posted\nTap on a video to change thumbnail' - : "Here you'll see list of videos which are either in video encoding process or deleted."; return Padding( padding: const EdgeInsets.only( top: 15.0, left: 15, right: 15, bottom: 20), child: Text( - text, + headerText, textAlign: TextAlign.center, style: TextStyle(color: Theme.of(context).primaryColorLight), ), @@ -352,10 +394,22 @@ class _MyAccountScreenState extends State ); } + String get headerText { + if (currentIndex == 0) { + return 'Videos NOT YET posted\nTap on a video to edit details & publish'; + } else if (currentIndex == 1) { + return 'Following videos are already posted\nTap on a video to change thumbnail'; + } else { + return "Videos which are under processing"; + } + } + Widget _videosList(List items, HiveUserData user) { - log(items.first.created); var published = items.where((item) => item.status == 'published').toList(); var ready = items.where((item) => item.status == 'publish_manual').toList(); + // items.forEach((element) { + // log(element.status); + // }); var failed = items .where((item) => item.status == 'encoding_failed' || @@ -368,6 +422,8 @@ class _MyAccountScreenState extends State item.status != 'encoding_failed' && item.status.toLowerCase() != 'deleted') .toList(); + var delted = + items.where((item) => item.status.toLowerCase() == 'deleted').toList(); var processAndFailed = process + failed; processAndFailed.sort((a, b) { DateTime dateA = DateTime.parse(a.created); @@ -389,6 +445,9 @@ class _MyAccountScreenState extends State SafeArea( child: _listViewForItems(processAndFailed, user), ), + // SafeArea( + // child: _listViewForItems(delted, user), + // ), ], ); } @@ -448,7 +507,7 @@ class _MyAccountScreenState extends State @override Widget build(BuildContext context) { return DefaultTabController( - length: 4, + length: 3, child: Scaffold( appBar: _appBar(widget.data.username ?? 'sagarkothari88'), body: SafeArea( diff --git a/lib/src/screens/podcast/view/local_podcast_episode.dart b/lib/src/screens/podcast/view/local_podcast_episode.dart index e9dd00da..79b83f00 100644 --- a/lib/src/screens/podcast/view/local_podcast_episode.dart +++ b/lib/src/screens/podcast/view/local_podcast_episode.dart @@ -89,56 +89,78 @@ class LocalEpisodeListView extends StatelessWidget { item.enclosureUrl = '$url'; } return ListTile( - onTap: () { - GetAudioPlayer audioPlayer = GetAudioPlayer(); - audioPlayer.audioHandler.updateQueue([]); - audioPlayer.audioHandler.addQueueItem( - MediaItem( - id: url, - title: item.title ?? "", - artUri: Uri.parse(item.image ?? ""), - duration: Duration(seconds: item.duration ?? 0), - ), - ); - var screen = Scaffold( - appBar: AppBar( - title: ListTile( - leading: CachedImage( - imageUrl: item.image ?? '', - imageHeight: 40, - imageWidth: 40, + onTap: () { + GetAudioPlayer audioPlayer = GetAudioPlayer(); + audioPlayer.audioHandler.updateQueue([]); + audioPlayer.audioHandler.addQueueItem( + MediaItem( + id: url, + title: item.title ?? "", + artUri: Uri.parse(item.image ?? ""), + duration: Duration(seconds: item.duration ?? 0), + ), + ); + var screen = Scaffold( + appBar: AppBar( + title: ListTile( + leading: CachedImage( + imageUrl: item.image ?? '', + imageHeight: 40, + imageWidth: 40, + ), + title: Text(item.title ?? 'No Title'), ), - title: Text(item.title ?? 'No Title'), ), - ), - body: SafeArea( - child: NewPodcastEpidosePlayer( - podcastEpisodes: [item], + body: SafeArea( + child: NewPodcastEpidosePlayer( + podcastEpisodes: [item], + ), ), - ), - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - leading: Container( - height: 30, - width: 30, - decoration: BoxDecoration( - color: Colors.grey, - image: (isOffline && !item.image!.startsWith('http')) - ? DecorationImage( - image: FileImage(File(item.image!)), fit: BoxFit.cover) - : DecorationImage( - image: NetworkImage( - item.image ?? "", - ), - )), - ), - title: Text( - item.title ?? '', - maxLines: 2, - style: Theme.of(context).textTheme.titleSmall, - ), - ); + ); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + leading: Container( + height: 30, + width: 30, + decoration: BoxDecoration( + color: Colors.grey, + image: (isOffline && !item.image!.startsWith('http')) + ? DecorationImage( + image: FileImage(File(item.image!)), fit: BoxFit.cover) + : DecorationImage( + image: NetworkImage( + item.image ?? "", + ), + )), + ), + title: Text( + item.title ?? '', + maxLines: 2, + style: Theme.of(context).textTheme.titleSmall, + ), + trailing: fileSizeWidget(item.enclosureUrl)); + } + + Widget? fileSizeWidget(String? enclosureUrl) { + if (enclosureUrl == null) return null; + try { + return isOffline + ? Text(formatBytes(File(enclosureUrl).lengthSync())) + : null; + } catch (e) { + return null; + } + } + + String formatBytes(int bytes) { + const suffixes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + int i = 0; + double size = bytes.toDouble(); + while (size > 1024 && i < suffixes.length - 1) { + size /= 1024; + i++; + } + return "${size.toStringAsFixed(2)} ${suffixes[i]}"; } } diff --git a/lib/src/screens/search/search_screen.dart b/lib/src/screens/search/search_screen.dart index 456dc775..e238fb64 100644 --- a/lib/src/screens/search/search_screen.dart +++ b/lib/src/screens/search/search_screen.dart @@ -1,9 +1,10 @@ import 'dart:async'; import 'dart:developer'; + import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:acela/src/utils/graphql/models/trending_feed_response.dart'; -import 'package:acela/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -50,7 +51,7 @@ class _SearchScreenState extends State { title: TextField( controller: _controller, onChanged: (value) { - var timer = Timer(const Duration(seconds: 2), () { + var timer = Timer(const Duration(seconds: 1), () { log('Text changed to $value'); if (value.trim().length > 3) { search(value.trim(), appData); @@ -93,12 +94,20 @@ class _SearchScreenState extends State { Widget _searchResultListView(HiveUserData appData) { if (results.isEmpty && !loading) { - return const Center( + return Center( child: Text('No search result found'), ); } else if (loading) { - return const Center( - child: Text('Loading search results....'), + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center(child: CircularProgressIndicator()), + const SizedBox( + height: 10, + ), + Center(child: Text('Loading search results....')), + ], ); } return _searchResults(appData); diff --git a/lib/src/screens/upload/video/video_upload_screen.dart b/lib/src/screens/upload/video/video_upload_screen.dart index 3e8d9969..fcfc5955 100644 --- a/lib/src/screens/upload/video/video_upload_screen.dart +++ b/lib/src/screens/upload/video/video_upload_screen.dart @@ -1,5 +1,7 @@ import 'dart:io'; + import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/my_account/my_account_screen.dart'; import 'package:acela/src/screens/upload/video/controller/video_upload_controller.dart'; import 'package:acela/src/screens/upload/video/widgets/beneficaries_tile.dart'; import 'package:acela/src/screens/upload/video/widgets/community_picker.dart'; @@ -8,6 +10,7 @@ import 'package:acela/src/screens/upload/video/widgets/reward_type_widget.dart'; import 'package:acela/src/screens/upload/video/widgets/thumbnail_picker.dart'; import 'package:acela/src/screens/upload/video/widgets/uploadProgressExpansionTile.dart'; import 'package:acela/src/screens/upload/video/widgets/upload_textfield.dart'; +import 'package:acela/src/screens/upload/video/widgets/video_upload_divider.dart'; import 'package:acela/src/screens/upload/video/widgets/work_type_widget.dart'; import 'package:acela/src/utils/enum.dart'; import 'package:acela/src/widgets/loading_screen.dart'; @@ -22,8 +25,8 @@ class VideoUploadScreen extends StatefulWidget { : super(key: key); final HiveUserData appData; - final bool isCamera; + final bool isCamera; @override State createState() => _VideoUploadScreenState(); } @@ -60,7 +63,7 @@ class _VideoUploadScreenState extends State { floatingActionButton: saveButton(controller), body: SafeArea( child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 15), + padding: const EdgeInsets.symmetric(vertical: 15), child: ValueListenableBuilder( valueListenable: controller.isSaving, builder: (context, isPublishing, child) { @@ -80,6 +83,8 @@ class _VideoUploadScreenState extends State { } }, child: SingleChildScrollView( + keyboardDismissBehavior: + ScrollViewKeyboardDismissBehavior.onDrag, child: Column( children: [ UploadProgressExpandableTile( @@ -128,19 +133,20 @@ class _VideoUploadScreenState extends State { onChanged: (value) { controller.description = value; }), - const SizedBox(height: 15), communityTile(controller), - const SizedBox(height: 15), + const VideoUploadDivider(), _workType(controller), - const SizedBox(height: 15), + const VideoUploadDivider(), _rewardType(controller), - const SizedBox(height: 15), + const VideoUploadDivider(), _beneficiaryTile(controller), - const SizedBox(height: 15), + const VideoUploadDivider(), _languageTile(controller), - const SizedBox(height: 15), + const VideoUploadDivider(), _thumbnailPicker(controller), - const SizedBox(height: 50), + const SizedBox( + height: 50, + ) ], ), ), @@ -253,12 +259,21 @@ class _VideoUploadScreenState extends State { onPressed: () { Navigator.of(context).pop(); Navigator.of(context).pop(); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MyAccountScreen( + data: widget.appData, + initialTabIndex: 2, + ), + ), + ); }, ); AlertDialog alert = AlertDialog( title: Text("🎉 Upload Complete 🎉"), content: Text( - "✅ Your Video is in-process\n\n✅ Video has be added to encoding queue\n\n👀 Check status from My Account\n\n📝 Let's edit video details now."), + "✅ Your Video is in-process\n\n✅ Video has be added to encoding queue\n\n👀 Check status from My Account."), actions: [ okButton, ], diff --git a/lib/src/screens/upload/video/widgets/beneficaries_tile.dart b/lib/src/screens/upload/video/widgets/beneficaries_tile.dart index f5c683ad..1e761445 100644 --- a/lib/src/screens/upload/video/widgets/beneficaries_tile.dart +++ b/lib/src/screens/upload/video/widgets/beneficaries_tile.dart @@ -1,6 +1,7 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/my_account/video_ops.dart'; import 'package:acela/src/screens/my_account/update_video/add_bene_sheet.dart'; +import 'package:acela/src/utils/constants.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; import 'package:acela/src/widgets/user_profile_image.dart'; import 'package:flutter/material.dart'; @@ -37,30 +38,33 @@ class _BeneficiariesTileState extends State { onTap: () { beneficiariesBottomSheet(context); }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Row( - children: [ - Text('Video Participants:'), - Spacer(), - Icon(Icons.arrow_drop_down), - ], - ), - Visibility( - visible: beneficiaries.isNotEmpty, - child: Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Wrap( - spacing: 10, - runSpacing: 10, - children: List.generate( - beneficiaries.length, - (index) => _beneficarieNameTile(theme, index, context), - ), - )), - ) - ], + child: Padding( + padding: const EdgeInsets.all(kScreenHorizontalPaddingDigit), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + Text('Video Participants:'), + Spacer(), + Icon(Icons.arrow_drop_down), + ], + ), + Visibility( + visible: beneficiaries.isNotEmpty, + child: Padding( + padding: const EdgeInsets.only(top: 12.0), + child: Wrap( + spacing: 10, + runSpacing: 10, + children: List.generate( + beneficiaries.length, + (index) => _beneficarieNameTile(theme, index, context), + ), + )), + ) + ], + ), ), ); } diff --git a/lib/src/screens/upload/video/widgets/community_picker.dart b/lib/src/screens/upload/video/widgets/community_picker.dart index cb8abfd7..1b0fb6a6 100644 --- a/lib/src/screens/upload/video/widgets/community_picker.dart +++ b/lib/src/screens/upload/video/widgets/community_picker.dart @@ -1,6 +1,8 @@ import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/screens/communities_screen/communities_screen.dart'; +import 'package:acela/src/utils/constants.dart'; import 'package:acela/src/widgets/custom_circle_avatar.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class CommunityPicker extends StatefulWidget { @@ -20,47 +22,71 @@ class CommunityPicker extends StatefulWidget { } class _CommunityPickerState extends State { - late String selectedCommunityName; - late String selectedCommunityId; - - @override - void initState() { - selectedCommunityId = widget.communityId; - selectedCommunityName = widget.communityName; - super.initState(); - } + String selectedCommunityName = ""; + String selectedCommunityId = ""; @override Widget build(BuildContext context) { - return InkWell( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (c) => CommunitiesScreen( - withoutScaffold: false, - didSelectCommunity: (name, id) { - setState(() { - selectedCommunityName = name; - selectedCommunityId = id; - }); - widget.onChanged(name, id); - }, + return Padding( + padding: const EdgeInsets.only(top: 8), + child: InkWell( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (c) => CommunitiesScreen( + withoutScaffold: false, + didSelectCommunity: (name, id) { + setState(() { + selectedCommunityName = name; + selectedCommunityId = id; + }); + widget.onChanged(name, id); + }, + ), ), + ); + }, + child: Padding( + padding: EdgeInsets.only( + left: kScreenHorizontalPaddingDigit, + right: kScreenHorizontalPaddingDigit, + top: 7), + child: Row( + children: [ + const Text('Select Community:'), + Spacer(), + Stack( + alignment: Alignment.centerRight, + children: [ + Visibility( + visible: selectedCommunityId.isNotEmpty && + selectedCommunityName.isNotEmpty, + maintainState: true, + maintainSemantics: true, + maintainSize: true, + maintainAnimation: true, + child: Row( + children: [ + Text(selectedCommunityName), + SizedBox(width: 10), + CustomCircleAvatar( + width: 44, + height: 44, + url: server.communityIcon(selectedCommunityId), + ), + ], + ), + ), + Visibility( + visible: selectedCommunityId.isEmpty || + selectedCommunityName.isEmpty, + child: Icon(Icons.arrow_drop_down), + ), + ], + ) + ], ), - ); - }, - child: Row( - children: [ - const Text('Select Community:'), - Spacer(), - Text(selectedCommunityName), - SizedBox(width: 10), - CustomCircleAvatar( - width: 44, - height: 44, - url: server.communityIcon(selectedCommunityId), - ), - ], + ), ), ); } diff --git a/lib/src/screens/upload/video/widgets/language_tile.dart b/lib/src/screens/upload/video/widgets/language_tile.dart index 1d376f27..84dfce77 100644 --- a/lib/src/screens/upload/video/widgets/language_tile.dart +++ b/lib/src/screens/upload/video/widgets/language_tile.dart @@ -1,4 +1,5 @@ import 'package:acela/src/screens/settings/settings_screen.dart'; +import 'package:acela/src/utils/constants.dart'; import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:flutter/material.dart'; @@ -44,7 +45,7 @@ class _LanguageTileState extends State { @override Widget build(BuildContext context) { return ListTile( - contentPadding: EdgeInsets.zero, + contentPadding: kScreenHorizontalPadding, leading: const Icon(Icons.language), title: const Text("Set Language Filter"), trailing: Text(selectedLanguage.name), diff --git a/lib/src/screens/upload/video/widgets/reward_type_widget.dart b/lib/src/screens/upload/video/widgets/reward_type_widget.dart index 4cfc2da1..de396e4f 100644 --- a/lib/src/screens/upload/video/widgets/reward_type_widget.dart +++ b/lib/src/screens/upload/video/widgets/reward_type_widget.dart @@ -1,3 +1,4 @@ +import 'package:acela/src/utils/constants.dart'; import 'package:flutter/material.dart'; class RewardTypeWidget extends StatefulWidget { @@ -23,20 +24,23 @@ class _RewardTypeWidgetState extends State { @override Widget build(BuildContext context) { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(isPower100 ? '100% power' : '50% power'), - Switch( - value: isPower100, - onChanged: (newValue) { - setState(() { - isPower100 = newValue; - }); - widget.onChanged(newValue); - }, - ) - ], + return Padding( + padding: kScreenHorizontalPadding, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(isPower100 ? '100% power' : '50% power'), + Switch( + value: isPower100, + onChanged: (newValue) { + setState(() { + isPower100 = newValue; + }); + widget.onChanged(newValue); + }, + ) + ], + ), ); } } diff --git a/lib/src/screens/upload/video/widgets/thumbnail_picker.dart b/lib/src/screens/upload/video/widgets/thumbnail_picker.dart index 72756fc1..6504f440 100644 --- a/lib/src/screens/upload/video/widgets/thumbnail_picker.dart +++ b/lib/src/screens/upload/video/widgets/thumbnail_picker.dart @@ -1,4 +1,5 @@ import 'package:acela/src/models/video_upload/upload_response.dart'; +import 'package:acela/src/utils/constants.dart'; import 'package:acela/src/utils/enum.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; @@ -26,45 +27,82 @@ class _ThumbnailPickerState extends State { @override Widget build(BuildContext context) { final theme = Theme.of(context); - return SizedBox( - width: 320, - height: 160, - child: ValueListenableBuilder( - valueListenable: widget.thumbnailUploadStatus, - builder: (context, uploadStatus, child) { - return InkWell( - child: ValueListenableBuilder( - valueListenable: widget.thumbnailUploadProgress, - builder: (context, progress, child) { - return Center( - child: uploadStatus == UploadStatus.started - ? CircularProgressIndicator( - value: progress, - valueColor: AlwaysStoppedAnimation( - theme.primaryColorLight), - backgroundColor: !isPickingImage - ? theme.primaryColorLight.withOpacity(0.4) - : null, - ) - : ValueListenableBuilder( - valueListenable: widget.thumbnailUploadRespone, - builder: (context, value, child) { - return value != null - ? Image.network( value.url) - : const Text( - 'Tap here to add thumbnail for your video\n\nThumbnail is MANDATORY to set.', - textAlign: TextAlign.center); - }, - ), - ); - }, - ), - onTap: () async { - await _onTap(uploadStatus); - }, - ); + return ValueListenableBuilder( + valueListenable: widget.thumbnailUploadStatus, + builder: (context, uploadStatus, child) { + return InkWell( + child: Padding( + padding: const EdgeInsets.all(kScreenHorizontalPaddingDigit), + child: Column( + children: [ + Stack( + children: [ + Positioned( + top: 10, + right: 10, + child: Icon( + Icons.emergency, + size: 15, + color: Colors.red, + )), + Container( + color: theme.cardColor.withOpacity(0.5), + width: 320, + height: 160, + child: ValueListenableBuilder( + valueListenable: widget.thumbnailUploadProgress, + builder: (context, progress, child) { + return Center( + child: uploadStatus == UploadStatus.started + ? CircularProgressIndicator( + value: progress, + valueColor: AlwaysStoppedAnimation( + theme.primaryColorLight), + backgroundColor: !isPickingImage + ? theme.primaryColorLight + .withOpacity(0.4) + : null, + ) + : ValueListenableBuilder( + valueListenable: + widget.thumbnailUploadRespone, + builder: (context, value, child) { + return value != null + ? Image.network(value.url) + : const SizedBox.shrink(); + }, + ), + ); + }, + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.upload), + const SizedBox( + width: 7, + ), + Text( + "Tap here to set thumbnail", + style: TextStyle(color: Colors.red), + ), + ], + ), + ), + ], + ), + ), + onTap: () async { + await _onTap(uploadStatus); }, - )); + ); + }, + ); } Future _onTap(UploadStatus uploadStatus) async { @@ -92,7 +130,7 @@ class _ThumbnailPickerState extends State { } } - void showError(String string) { + void showError(String string) { var snackBar = SnackBar(content: Text('Error: $string')); ScaffoldMessenger.of(context).showSnackBar(snackBar); } diff --git a/lib/src/screens/upload/video/widgets/uploadProgressExpansionTile.dart b/lib/src/screens/upload/video/widgets/uploadProgressExpansionTile.dart index 68e43d8b..9b248d02 100644 --- a/lib/src/screens/upload/video/widgets/uploadProgressExpansionTile.dart +++ b/lib/src/screens/upload/video/widgets/uploadProgressExpansionTile.dart @@ -1,3 +1,4 @@ +import 'package:acela/src/utils/constants.dart'; import 'package:acela/src/utils/enum.dart'; import 'package:flutter/material.dart'; @@ -40,61 +41,64 @@ class _UploadProgressExpandableTileState @override Widget build(BuildContext context) { - return ExpansionPanelList( - expandedHeaderPadding: const EdgeInsets.only(top: 0), - elevation: 0, - expansionCallback: (int index, bool isExpanded) { - setState( - () { - this.isExpanded = isExpanded; - }, - ); - }, - children: [ - ExpansionPanel( - headerBuilder: (BuildContext context, bool isExpanded) { - return SizedBox( - height: 55, - child: Stack( - children: [ - PageView( - physics: const NeverScrollableScrollPhysics(), - onPageChanged: (value) { - setState( - () { - _pageIndex = value; - }, - ); - }, - controller: widget.pageController, - scrollDirection: Axis.vertical, - children: _uploadWidgets( - showStartEndWidgets: true, showWidgets: !isExpanded), - ), - Visibility( - visible: isExpanded, - child: ValueListenableBuilder( - valueListenable: widget.uploadStatus, - builder: (context, uploadStatus, child) { - return ListTile( - title: Text( - uploadStatusString(uploadStatus), - ), + return Padding( + padding: kScreenHorizontalPadding, + child: ExpansionPanelList( + expandedHeaderPadding: const EdgeInsets.only(top: 0), + elevation: 0, + expansionCallback: (int index, bool isExpanded) { + setState( + () { + this.isExpanded = isExpanded; + }, + ); + }, + children: [ + ExpansionPanel( + headerBuilder: (BuildContext context, bool isExpanded) { + return SizedBox( + height: 55, + child: Stack( + children: [ + PageView( + physics: const NeverScrollableScrollPhysics(), + onPageChanged: (value) { + setState( + () { + _pageIndex = value; + }, ); }, + controller: widget.pageController, + scrollDirection: Axis.vertical, + children: _uploadWidgets( + showStartEndWidgets: true, showWidgets: !isExpanded), ), - ), - ], - ), - ); - }, - body: Column( - children: - _uploadWidgets(showStartEndWidgets: false, showWidgets: true), + Visibility( + visible: isExpanded, + child: ValueListenableBuilder( + valueListenable: widget.uploadStatus, + builder: (context, uploadStatus, child) { + return ListTile( + title: Text( + uploadStatusString(uploadStatus), + ), + ); + }, + ), + ), + ], + ), + ); + }, + body: Column( + children: + _uploadWidgets(showStartEndWidgets: false, showWidgets: true), + ), + isExpanded: isExpanded, ), - isExpanded: isExpanded, - ), - ], + ], + ), ); } diff --git a/lib/src/screens/upload/video/widgets/upload_textfield.dart b/lib/src/screens/upload/video/widgets/upload_textfield.dart index 8d2ad7f5..d2b74b43 100644 --- a/lib/src/screens/upload/video/widgets/upload_textfield.dart +++ b/lib/src/screens/upload/video/widgets/upload_textfield.dart @@ -1,3 +1,4 @@ +import 'package:acela/src/utils/constants.dart'; import 'package:flutter/material.dart'; class UploadTextField extends StatelessWidget { @@ -23,21 +24,24 @@ class UploadTextField extends StatelessWidget { @override Widget build(BuildContext context) { final theme = Theme.of(context); - return TextField( - controller: textEditingController, - decoration: InputDecoration( - border: border(), - filled: true, - isDense: true, - fillColor: theme.cardColor, - hintText: hintText, - labelText: labelText, - suffixIcon: _clearButton(), + return Padding( + padding: kScreenHorizontalPadding, + child: TextField( + controller: textEditingController, + decoration: InputDecoration( + border: border(), + filled: true, + isDense: true, + fillColor: theme.cardColor, + hintText: hintText, + labelText: labelText, + suffixIcon: _clearButton(), + ), + onChanged: onChanged, + maxLines: maxLines, + minLines: minLines, + maxLength: maxLength, ), - onChanged: onChanged, - maxLines: maxLines, - minLines: minLines, - maxLength: maxLength, ); } diff --git a/lib/src/screens/upload/video/widgets/video_upload_divider.dart b/lib/src/screens/upload/video/widgets/video_upload_divider.dart new file mode 100644 index 00000000..126a284c --- /dev/null +++ b/lib/src/screens/upload/video/widgets/video_upload_divider.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; + +class VideoUploadDivider extends StatelessWidget { + const VideoUploadDivider({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Divider( + color: Theme.of(context).cardColor.withOpacity(0.7), + ); + } +} diff --git a/lib/src/screens/upload/video/widgets/work_type_widget.dart b/lib/src/screens/upload/video/widgets/work_type_widget.dart index 95389930..93a5bd54 100644 --- a/lib/src/screens/upload/video/widgets/work_type_widget.dart +++ b/lib/src/screens/upload/video/widgets/work_type_widget.dart @@ -1,5 +1,5 @@ +import 'package:acela/src/utils/constants.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; class WorkTypeWidget extends StatefulWidget { const WorkTypeWidget( @@ -24,25 +24,28 @@ class _WorkTypeWidgetState extends State { @override Widget build(BuildContext context) { - return Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Checkbox( - visualDensity: VisualDensity.compact, - value: isNsfwContent, onChanged: (newValue) { - setState(() { - isNsfwContent = newValue!; - }); - widget.onChanged(newValue!); - },), - Expanded( - child: Text( - "You should check this option if your content is NSFW", - style: TextStyle(color: Colors.red), - ), - ), - - ], + return Padding( + padding: EdgeInsets.all(kScreenHorizontalPaddingDigit), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Checkbox( + visualDensity: VisualDensity.compact, + value: isNsfwContent, onChanged: (newValue) { + setState(() { + isNsfwContent = newValue!; + }); + widget.onChanged(newValue!); + },), + Expanded( + child: Text( + "You should check this option if your content is NSFW", + style: TextStyle(color: Colors.red), + ), + ), + + ], + ), ); } } diff --git a/lib/src/utils/constants.dart b/lib/src/utils/constants.dart new file mode 100644 index 00000000..6a05a0fa --- /dev/null +++ b/lib/src/utils/constants.dart @@ -0,0 +1,5 @@ +import 'package:flutter/cupertino.dart'; + +const kScreenHorizontalPaddingDigit = 15.0; +const kScreenHorizontalPadding = + EdgeInsets.symmetric(horizontal: kScreenHorizontalPaddingDigit); diff --git a/lib/src/utils/graphql/gql_communicator.dart b/lib/src/utils/graphql/gql_communicator.dart index ef2bc4d7..ab81edc3 100644 --- a/lib/src/utils/graphql/gql_communicator.dart +++ b/lib/src/utils/graphql/gql_communicator.dart @@ -25,7 +25,6 @@ class GQLCommunicator { 'content-type': 'application/json', }; var request = http.Request('POST', Uri.parse(gqlServer)); - log('Query is - $query'); request.body = json .encode({"query": query, "operationName": operation, "extensions": {}}); request.headers.addAll(headers); From 4e1087ff48be7ff97730795729ac7d9449ca2ae9 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Mon, 8 Apr 2024 20:52:52 +0530 Subject: [PATCH 393/466] use file manager for podcast upload instead of Apple Music --- .idea/libraries/Dart_SDK.xml | 40 ++++++++++--------- .../upload/podcast/podcast_upload_screen.dart | 29 ++++++-------- 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml index 6cba42fc..d4bb4d42 100644 --- a/.idea/libraries/Dart_SDK.xml +++ b/.idea/libraries/Dart_SDK.xml @@ -1,25 +1,27 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/src/screens/upload/podcast/podcast_upload_screen.dart b/lib/src/screens/upload/podcast/podcast_upload_screen.dart index ca112535..504a46c8 100644 --- a/lib/src/screens/upload/podcast/podcast_upload_screen.dart +++ b/lib/src/screens/upload/podcast/podcast_upload_screen.dart @@ -112,12 +112,9 @@ class _PodcastUploadScreenState extends State { didShowFilePicker = true; }); - FilePickerResult? pickerResult = - await FilePicker.platform.pickFiles(type: FileType.audio); + FilePickerResult? pickerResult = await FilePicker.platform.pickFiles(type: Platform.isIOS ? FileType.any : FileType.audio); final XFile? file; - file = pickerResult != null - ? XFile(pickerResult.files.single.path ?? "") - : null; + file = pickerResult != null ? XFile(pickerResult.files.single.path ?? "") : null; if (file != null) { setState(() { didPickFile = true; @@ -127,14 +124,17 @@ class _PodcastUploadScreenState extends State { setState(() { fileName = originalFileName; }); - var fileToSave = File(file.path); log(originalFileName); log("path - ${file.path}"); var alreadyUploaded = list.items.contains((e) { return e.fileName == originalFileName || e.filePath == file!.path; }); + var extension = file.path.split(".").last; + if (extension != "mp3") { + throw 'Podcast should be in mp3 format.'; + } if (alreadyUploaded) { - throw 'This video is already uploaded by you'; + throw 'This podcast is already uploaded by you'; } var size = await file.length(); var dateEndGettingVideo = DateTime.now(); @@ -156,11 +156,9 @@ class _PodcastUploadScreenState extends State { throw 'Podcast Episode is too big to be uploaded from mobile (exceeding 500 mb)'; } var path = file.path; - MediaInformationSession session = - await FFprobeKit.getMediaInformation(path); + MediaInformationSession session = await FFprobeKit.getMediaInformation(path); var info = session.getMediaInformation(); - var duration = - (double.tryParse(info?.getDuration() ?? "0.0") ?? 0.0).toInt(); + var duration = (double.tryParse(info?.getDuration() ?? "0.0") ?? 0.0).toInt(); log('Podcast Episode duration is $duration'); setState(() { this.duration = duration; @@ -176,8 +174,7 @@ class _PodcastUploadScreenState extends State { tusFileName = name; }); _addItem(originalFileName, file.path); - showMessage( - 'Podcast Episode Audio is uploaded. Hit Next to finish next action items to publish podcast episode.'); + showMessage('Podcast Episode Audio is uploaded. Hit Next to finish next action items to publish podcast episode.'); showMyDialog(); // Step 6. Move Video to Queue } else { @@ -213,8 +210,7 @@ class _PodcastUploadScreenState extends State { nowButton, ], ); - showDialog( - context: context, builder: (c) => alert, barrierDismissible: false); + showDialog(context: context, builder: (c) => alert, barrierDismissible: false); } void showMessage(String string) { @@ -294,8 +290,7 @@ class _PodcastUploadScreenState extends State { body: ListView( children: [ ListTile( - title: Text( - 'Uploading Audio (${didUpload ? 100.0 : (progress * 100).toStringAsFixed(2)}%)'), + title: Text('Uploading Audio (${didUpload ? 100.0 : (progress * 100).toStringAsFixed(2)}%)'), trailing: !didStartUpload ? const Icon(Icons.pending) : !didUpload From d814e35f3c05088d86f008aff1bd6cf05e5f1543 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 9 Apr 2024 19:54:22 +0530 Subject: [PATCH 394/466] version bump --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index af4b5581..4be54761 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.5.0+91 +version: 2.5.1+92 environment: sdk: ">=2.15.1 <3.0.0" From 63c19d94db7bc6dba2e41efd0b56914b82d6538e Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 9 Apr 2024 20:14:53 +0530 Subject: [PATCH 395/466] uploaded to AppStore --- ios/Runner.xcodeproj/project.pbxproj | 9 +++------ pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 98142e8b..9e8bfdd1 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -460,10 +460,9 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 91; + CURRENT_PROJECT_VERSION = "${FLUTTER_BUILD_NUMBER}"; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; - FLUTTER_BUILD_NUMBER = 91; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = 3Speak.tv; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.video"; @@ -606,10 +605,9 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 91; + CURRENT_PROJECT_VERSION = "${FLUTTER_BUILD_NUMBER}"; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; - FLUTTER_BUILD_NUMBER = 91; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = 3Speak.tv; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.video"; @@ -638,10 +636,9 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 91; + CURRENT_PROJECT_VERSION = "${FLUTTER_BUILD_NUMBER}"; DEVELOPMENT_TEAM = 58LRY57FMK; ENABLE_BITCODE = NO; - FLUTTER_BUILD_NUMBER = 91; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = 3Speak.tv; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.video"; diff --git a/pubspec.yaml b/pubspec.yaml index 4be54761..f8f322ff 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.5.1+92 +version: 2.5.1+93 environment: sdk: ">=2.15.1 <3.0.0" From 9d42a1ad604444a11287911e9c90af315fdcb979 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 18 Apr 2024 08:23:50 +0530 Subject: [PATCH 396/466] uploading a new version on AppStore --- lib/src/screens/upload/podcast/podcast_upload_screen.dart | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/screens/upload/podcast/podcast_upload_screen.dart b/lib/src/screens/upload/podcast/podcast_upload_screen.dart index 504a46c8..24500473 100644 --- a/lib/src/screens/upload/podcast/podcast_upload_screen.dart +++ b/lib/src/screens/upload/podcast/podcast_upload_screen.dart @@ -130,8 +130,8 @@ class _PodcastUploadScreenState extends State { return e.fileName == originalFileName || e.filePath == file!.path; }); var extension = file.path.split(".").last; - if (extension != "mp3") { - throw 'Podcast should be in mp3 format.'; + if (!(extension == "mp3" || extension == "m4a")) { + throw 'Podcast should be in mp3/m4a format.'; } if (alreadyUploaded) { throw 'This podcast is already uploaded by you'; diff --git a/pubspec.yaml b/pubspec.yaml index f8f322ff..8d72d5e0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.5.1+93 +version: 2.5.2+94 environment: sdk: ">=2.15.1 <3.0.0" From 6da4949354a3bb2d0cf7a2c9fac2d72118dc9bbf Mon Sep 17 00:00:00 2001 From: sagar Date: Thu, 18 Apr 2024 15:26:46 +0530 Subject: [PATCH 397/466] podcast player duration continues from where user left off --- lib/src/models/my_account/video_ops.dart | 7 ++- .../update_video/add_bene_sheet.dart | 2 +- .../controller/podcast_controller.dart | 18 +++++-- .../podcast/view/local_podcast_episode.dart | 19 ++++++++ .../screens/podcast/view/podcasts_feed.dart | 2 - .../audio_player_core_controls.dart | 15 ++++++ .../new_pod_cast_epidose_player.dart | 27 ++++++++++- .../control_buttons.dart | 16 +++++++ .../podcast_player_slider.dart | 21 ++++++++- .../controller/video_upload_controller.dart | 32 ++++++++++--- .../video/widgets/beneficaries_tile.dart | 47 ++++++++++--------- 11 files changed, 165 insertions(+), 41 deletions(-) diff --git a/lib/src/models/my_account/video_ops.dart b/lib/src/models/my_account/video_ops.dart index 4ad59316..5ec516cd 100644 --- a/lib/src/models/my_account/video_ops.dart +++ b/lib/src/models/my_account/video_ops.dart @@ -35,11 +35,13 @@ class BeneficiariesJson { final String account; int weight; final String src; + final bool isDefault; BeneficiariesJson({ required this.account, required this.weight, required this.src, + this.isDefault = false }); factory BeneficiariesJson.fromJson(Map? json) => @@ -51,9 +53,7 @@ class BeneficiariesJson { static List fromJsonString(String jsonString) { var list = json.decode(jsonString) as List; - var listNew = list - .map((e) => BeneficiariesJson.fromJson(e)) - .toList(); + var listNew = list.map((e) => BeneficiariesJson.fromJson(e)).toList(); return listNew; } @@ -68,5 +68,4 @@ class BeneficiariesJson { 'src': src, }; } - } diff --git a/lib/src/screens/my_account/update_video/add_bene_sheet.dart b/lib/src/screens/my_account/update_video/add_bene_sheet.dart index 37d690e3..c35b9e14 100644 --- a/lib/src/screens/my_account/update_video/add_bene_sheet.dart +++ b/lib/src/screens/my_account/update_video/add_bene_sheet.dart @@ -13,7 +13,7 @@ class AddBeneSheet extends StatefulWidget { required this.onSave, }) : super(key: key); final List benes; - final Function onSave; + final Function(List newBenes) onSave; @override State createState() => _AddBeneSheetState(); diff --git a/lib/src/screens/podcast/controller/podcast_controller.dart b/lib/src/screens/podcast/controller/podcast_controller.dart index 248e7257..42ab36b6 100644 --- a/lib/src/screens/podcast/controller/podcast_controller.dart +++ b/lib/src/screens/podcast/controller/podcast_controller.dart @@ -9,9 +9,11 @@ import 'package:path_provider/path_provider.dart'; class PodcastController extends ChangeNotifier { final box = GetStorage(); + final durationStorage = GetStorage('duration_storage'); final String _likedPodcastEpisodeLocalKey = 'liked_podcast_episode'; final String _likedPodcastLocalKey = 'liked_podcast'; final String _offlinePodcastLocalKey = 'offline_podcast'; + bool isDurationContinuing = true; var externalDir; PodcastController() { @@ -89,7 +91,9 @@ class PodcastController extends ChangeNotifier { if (!filterOnlyRssPodcasts) { items.add(PodCastFeedItem.fromJson(item)); } else if (item['rssUrl'] != null) { - items.add(PodCastFeedItem.fromJson(item)); + items.add(PodCastFeedItem.fromJson( + item, + )); } } return items; @@ -165,8 +169,8 @@ class PodcastController extends ChangeNotifier { log('saving'); PodcastEpisode localEpisode = episode; try { - localEpisode = - episode.copyWith(image: await _saveImage(episode.image!, episode.id!)); + localEpisode = episode.copyWith( + image: await _saveImage(episode.image!, episode.id!)); } catch (e) {} final String key = _offlinePodcastLocalKey; if (box.read(key) != null) { @@ -234,4 +238,12 @@ class PodcastController extends ChangeNotifier { } } catch (e) {} } + + int? readSavedDurationOfEpisode(String id, String url) { + return durationStorage.read('${id}_$url'); + } + + writeDurationOfEpisode(String id, String url, int value) { + durationStorage.write('${id}_$url', value); + } } diff --git a/lib/src/screens/podcast/view/local_podcast_episode.dart b/lib/src/screens/podcast/view/local_podcast_episode.dart index 79b83f00..1c804d77 100644 --- a/lib/src/screens/podcast/view/local_podcast_episode.dart +++ b/lib/src/screens/podcast/view/local_podcast_episode.dart @@ -7,6 +7,7 @@ import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; import 'package:acela/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart'; import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; import 'package:acela/src/widgets/cached_image.dart'; +import 'package:acela/src/widgets/confirmation_dialog.dart'; import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -64,6 +65,24 @@ class LocalEpisodeListView extends StatelessWidget { return Dismissible( key: Key(item.id.toString()), background: Center(child: Text("Delete")), + confirmDismiss: (direction) async { + if (isOffline) { + bool delete = false; + await showDialog( + context: context, + builder: (context) => ConfirmationDialog( + title: "Delete", + content: + "Are you sure you want to delete this episode ", + onConfirm: () { + delete = true; + }), + ).whenComplete(() => null); + return Future.value(delete); + } else { + return Future.value(true); + } + }, onDismissed: (direction) { if (isOffline) { controller.deleteOfflinePodcastEpisode(item); diff --git a/lib/src/screens/podcast/view/podcasts_feed.dart b/lib/src/screens/podcast/view/podcasts_feed.dart index 7a733323..7f3fc4e0 100644 --- a/lib/src/screens/podcast/view/podcasts_feed.dart +++ b/lib/src/screens/podcast/view/podcasts_feed.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:acela/src/models/podcast/podcast_episodes.dart'; import 'package:acela/src/models/podcast/trending_podcast_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; diff --git a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart index 1765d6c6..ef84d8e3 100644 --- a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart +++ b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart @@ -58,6 +58,8 @@ abstract class AudioPlayerHandler implements AudioHandler { String url, ); + Future currentPosition(); + void disposeVideoController(); bool isVideo = false; @@ -338,6 +340,19 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler Future pause() => shouldPlayVideo() ? videoPlayerController!.pause() : _player.pause(); + Future currentPosition() async { + int duration = 0; + if (shouldPlayVideo()) { + var videoPosition = await videoPlayerController?.position; + if (videoPosition != null) { + duration = videoPosition.inSeconds; + } + } else { + duration = _player.position.inSeconds; + } + return duration; + } + @override Future seek(Duration position) => shouldPlayVideo() ? videoPlayerController!.seekTo(position) diff --git a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart index 6aafb5e5..ff3463fe 100644 --- a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart +++ b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart @@ -1,16 +1,17 @@ import 'dart:async'; import 'dart:developer'; + import 'package:acela/src/models/podcast/podcast_episode_chapters.dart'; import 'package:acela/src/models/podcast/podcast_episodes.dart'; import 'package:acela/src/screens/podcast/controller/podcast_chapters_controller.dart'; import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; +import 'package:acela/src/screens/podcast/widgets/audio_player/action_tools.dart'; +import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; import 'package:acela/src/screens/podcast/widgets/favourite.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_info_description.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart'; -import 'package:acela/src/screens/podcast/widgets/audio_player/action_tools.dart'; -import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; import 'package:acela/src/widgets/cached_image.dart'; import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; @@ -41,6 +42,7 @@ class _NewPodcastEpidosePlayerState extends State { List? chapters; late String originalTitle; late String? originalImage; + late Timer timer; Stream get _bufferedPositionStream => _audioHandler.playbackState .map((state) => state.bufferedPosition) @@ -64,6 +66,10 @@ class _NewPodcastEpidosePlayerState extends State { log(currentPodcastEpisode.enclosureUrl!); _setUpVideo(); podcastController = context.read(); + timer = Timer.periodic(Duration(seconds: 1), (t) { + writeCurrentDurationLocal(); + }); + podcastController.isDurationContinuing = true; originalImage = currentPodcastEpisode.image; originalTitle = currentPodcastEpisode.title!; // TO-DO: Ram to handle chapters for offline player @@ -88,13 +94,28 @@ class _NewPodcastEpidosePlayerState extends State { } } + void writeCurrentDurationLocal() async { + int seconds = await _audioHandler.currentPosition(); + if (seconds > 0) { + context.read().writeDurationOfEpisode( + currentPodcastEpisode.id!, + currentPodcastEpisode.enclosureUrl!, + seconds); + } + } + void _onEpisodeChange(data) { QueueState queueState = data as QueueState; if (currentPodcastIndex != queueState.queueIndex) { setState(() { currentPodcastIndex = queueState.queueIndex ?? 0; currentPodcastEpisode = widget.podcastEpisodes[currentPodcastIndex]; + podcastController.isDurationContinuing = true; _setUpVideo(); + timer.cancel(); + timer = Timer.periodic(Duration(seconds: 1), (t) { + writeCurrentDurationLocal(); + }); // if (currentPodcastEpisode.enclosureUrl != null && currentPodcastEpisode.enclosureUrl!.startsWith("http")) { chapterController = PodcastChapterController( chapterUrl: currentPodcastEpisode.chaptersUrl, @@ -110,6 +131,7 @@ class _NewPodcastEpidosePlayerState extends State { @override void dispose() { queueSubscription.cancel(); + timer.cancel(); super.dispose(); } @@ -186,6 +208,7 @@ class _NewPodcastEpidosePlayerState extends State { ), userToolbar(), PodcastPlayerSlider( + episode: currentPodcastEpisode, chapterController: chapterController, audioPlayerHandler: _audioHandler, positionDataStream: _positionDataStream, diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart index 95094971..92f8b3c8 100644 --- a/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart @@ -1,10 +1,12 @@ import 'package:acela/src/models/podcast/podcast_episodes.dart'; import 'package:acela/src/screens/podcast/controller/podcast_chapters_controller.dart'; +import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; import 'package:acela/src/screens/podcast/widgets/audio_player/action_tools.dart'; import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_intercation_icon_button.dart'; import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class ControlButtons extends StatelessWidget { final AudioPlayerHandler audioHandler; @@ -99,6 +101,7 @@ class ControlButtons extends StatelessWidget { ), ); } else { + _continueFromDuration(context); return GestureDetector( onTap: () { isPaused = !isPaused; @@ -155,6 +158,19 @@ class ControlButtons extends StatelessWidget { ); } + void _continueFromDuration(BuildContext context) { + final podcastController = context.read(); + if (podcastController.isDurationContinuing) { + int? skipToDuration = podcastController.readSavedDurationOfEpisode( + podcastEpisode.id!, podcastEpisode.enclosureUrl!); + podcastController.isDurationContinuing = true; + if (skipToDuration != null) { + audioHandler.seek(Duration(seconds: skipToDuration)); + } + podcastController.isDurationContinuing = false; + } + } + void _goForwardTenSeconds(PositionData positionData) { chapterController.currentDuration = chapterController.currentDuration + 10; chapterController.syncChapters(isInteracted: true, isReduced: false); diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart index d14ee82c..077ee7ec 100644 --- a/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart @@ -1,21 +1,29 @@ +import 'dart:developer'; + +import 'package:acela/src/models/podcast/podcast_episodes.dart'; import 'package:acela/src/screens/podcast/controller/podcast_chapters_controller.dart'; +import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; import 'package:acela/src/screens/podcast/widgets/audio_player/action_tools.dart'; import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class PodcastPlayerSlider extends StatelessWidget { const PodcastPlayerSlider( {Key? key, required this.chapterController, required this.audioPlayerHandler, - required this.currentPodcastEpisodeDuration, required this.positionDataStream}) + required this.currentPodcastEpisodeDuration, + required this.episode, + required this.positionDataStream}) : super(key: key); final PodcastChapterController chapterController; final AudioPlayerHandler audioPlayerHandler; final int? currentPodcastEpisodeDuration; final Stream positionDataStream; + final PodcastEpisode episode; @override Widget build(BuildContext context) { @@ -26,6 +34,7 @@ class PodcastPlayerSlider extends StatelessWidget { builder: (context, snapshot) { final positionData = snapshot.data ?? PositionData(Duration.zero, Duration.zero, Duration.zero); + // writeCurrentDurationLocal(context, positionData.position.inSeconds); var duration = currentPodcastEpisodeDuration?.toDouble() ?? 0.0; var pending = duration - positionData.position.inSeconds; var pendingText = "${Utilities.formatTime(pending.toInt())}"; @@ -54,6 +63,16 @@ class PodcastPlayerSlider extends StatelessWidget { ); } + void writeCurrentDurationLocal(BuildContext context, int seconds) { + Future.delayed(Duration(seconds: 10)).then((value) { + if (seconds > 0) { + log('writed'); + context.read().writeDurationOfEpisode( + episode.id!, episode.enclosureUrl!, seconds); + } + }); + } + void _onSlideChange(Duration newPosition) { chapterController.syncChapters( isInteracted: true, diff --git a/lib/src/screens/upload/video/controller/video_upload_controller.dart b/lib/src/screens/upload/video/controller/video_upload_controller.dart index 94335947..ab65bfbe 100644 --- a/lib/src/screens/upload/video/controller/video_upload_controller.dart +++ b/lib/src/screens/upload/video/controller/video_upload_controller.dart @@ -46,14 +46,32 @@ class VideoUploadController extends ChangeNotifier with Upload, VideoSaveMixin { void setBeneficiares({String? userName, bool resetBeneficiares = false}) { this.userName = userName ?? this.userName; if (beneficaries.isEmpty || resetBeneficiares) { - beneficaries = [ - BeneficiariesJson(account: 'sagarkothari88', src: 'mobile', weight: 1), - BeneficiariesJson( - account: 'spk.beneficiary', src: 'threespeak', weight: 9), - BeneficiariesJson( - account: 'threespeakleader', src: 'threespeak', weight: 1), + if (this.userName != 'sagarkothari88') { + beneficaries.add( + BeneficiariesJson( + account: 'sagarkothari88', + src: 'mobile', + weight: 1, + isDefault: true), + ); + } + if (this.userName != 'spk.beneficiary') { + beneficaries.add(BeneficiariesJson( + account: 'spk.beneficiary', + src: 'threespeak', + weight: 9, + isDefault: true)); + } + if (this.userName != 'threespeakleader') { + beneficaries.add(BeneficiariesJson( + account: 'threespeakleader', + src: 'threespeak', + weight: 1, + isDefault: true)); + } + beneficaries.add( BeneficiariesJson(account: this.userName, src: 'author', weight: 89), - ]; + ); } } diff --git a/lib/src/screens/upload/video/widgets/beneficaries_tile.dart b/lib/src/screens/upload/video/widgets/beneficaries_tile.dart index 1e761445..4d781501 100644 --- a/lib/src/screens/upload/video/widgets/beneficaries_tile.dart +++ b/lib/src/screens/upload/video/widgets/beneficaries_tile.dart @@ -55,8 +55,8 @@ class _BeneficiariesTileState extends State { child: Padding( padding: const EdgeInsets.only(top: 12.0), child: Wrap( - spacing: 10, - runSpacing: 10, + spacing: 0, + runSpacing: 0, children: List.generate( beneficiaries.length, (index) => _beneficarieNameTile(theme, index, context), @@ -69,27 +69,32 @@ class _BeneficiariesTileState extends State { ); } - Container _beneficarieNameTile( + Visibility _beneficarieNameTile( ThemeData theme, int index, BuildContext context) { - return Container( - padding: EdgeInsets.only(top: 2, bottom: 2, right: 8, left: 3), - decoration: BoxDecoration( - color: theme.cardColor, - borderRadius: BorderRadius.all(Radius.circular(20))), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - UserProfileImage(radius: 20, userName: beneficiaries[index].account), - const SizedBox( - width: 5, - ), - Text( - beneficiaries[index].account, - style: TextStyle( - color: Theme.of(context).primaryColorLight.withOpacity(0.7), + return Visibility( + visible: !beneficiaries[index].isDefault, + child: Container( + margin: EdgeInsets.only(right: 6, bottom: 8), + padding: EdgeInsets.only(top: 2, bottom: 2, right: 8, left: 3), + decoration: BoxDecoration( + color: theme.cardColor, + borderRadius: BorderRadius.all(Radius.circular(20))), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + UserProfileImage( + radius: 20, userName: beneficiaries[index].account), + const SizedBox( + width: 5, ), - ), - ], + Text( + beneficiaries[index].account, + style: TextStyle( + color: Theme.of(context).primaryColorLight.withOpacity(0.7), + ), + ), + ], + ), ), ); } From c5c15d6c56a6839cfa860b4ba7f3357ab44ec057 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sat, 20 Apr 2024 19:31:33 +0530 Subject: [PATCH 398/466] version bump - android play store release --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 8d72d5e0..d6e07ba3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.5.2+94 +version: 2.5.4+95 environment: sdk: ">=2.15.1 <3.0.0" From 1fda1e4a14cf3a093ef05b2dcc552eafd8081311 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Sat, 20 Apr 2024 20:25:44 +0530 Subject: [PATCH 399/466] version bump --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index d6e07ba3..192f4ba1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.5.4+95 +version: 2.5.4+97 environment: sdk: ">=2.15.1 <3.0.0" From 78d2db227a8ed1e66b216b687e0d2930ae2f2202 Mon Sep 17 00:00:00 2001 From: sagar Date: Tue, 23 Apr 2024 19:05:30 +0530 Subject: [PATCH 400/466] audio service crash fix --- lib/src/screens/podcast/view/podcasts_feed.dart | 5 +++++ .../widgets/audio_player/audio_player_core_controls.dart | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/src/screens/podcast/view/podcasts_feed.dart b/lib/src/screens/podcast/view/podcasts_feed.dart index 7f3fc4e0..32f470b8 100644 --- a/lib/src/screens/podcast/view/podcasts_feed.dart +++ b/lib/src/screens/podcast/view/podcasts_feed.dart @@ -30,6 +30,11 @@ class _PodcastFeedScreenState extends State { @override void initState() { super.initState(); + if (!GetAudioPlayer().audioHandler.isInitiated) { + GetAudioPlayer().audioHandler.isInitiated = true; + GetAudioPlayer().audioHandler.play(); + } + future = loadPodCastEpisode(); } diff --git a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart index ef84d8e3..e8a9bba1 100644 --- a/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart +++ b/lib/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart @@ -64,6 +64,8 @@ abstract class AudioPlayerHandler implements AudioHandler { bool isVideo = false; + bool isInitiated = false; + bool shouldPlayVideo(); } @@ -87,6 +89,7 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler final BehaviorSubject speed = BehaviorSubject.seeded(1.0); final _mediaItemExpando = Expando(); bool isVideo = false; + bool isInitiated = false; VideoPlayerController? videoPlayerController; ValueNotifier aspectRatioNotifier = ValueNotifier(null); @@ -239,7 +242,7 @@ class AudioPlayerHandlerImpl extends BaseAudioHandler .pipe(queue); // Load the playlist. _playlist.addAll(queue.value.map(_itemToSource).toList()); - await _player.setAudioSource(_playlist); + await _player.setAudioSource(_playlist, preload: false); } AudioSource _itemToSource(MediaItem mediaItem) { From c835adad33ebd8429bede60a2b4ef256a3fdffd6 Mon Sep 17 00:00:00 2001 From: sagar Date: Wed, 24 Apr 2024 13:20:49 +0530 Subject: [PATCH 401/466] updated firebase packages, story player crash fix --- lib/main.dart | 4 ++- lib/src/widgets/story_player.dart | 4 +-- pubspec.lock | 52 +++++++++++++++---------------- pubspec.yaml | 6 ++-- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 111bcf7f..cf9d724b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -109,7 +109,9 @@ class _MyAppState extends State { lazy: false, create: (context) => PodcastController(), ), - ChangeNotifierProvider(create: (context) => VideoSettingProvider()), + ChangeNotifierProvider( + lazy: false, + create: (context) => VideoSettingProvider()), ChangeNotifierProvider( lazy: false, create: (context) => SettingsProvider(), diff --git a/lib/src/widgets/story_player.dart b/lib/src/widgets/story_player.dart index 7b2f3377..2f55d6bb 100644 --- a/lib/src/widgets/story_player.dart +++ b/lib/src/widgets/story_player.dart @@ -46,6 +46,7 @@ class _StoryPlayerState extends State { late BetterPlayerController _betterPlayerController; HivePostInfoPostResultBody? postInfo; bool controlsVisible = false; + late final VideoSettingProvider videoSettingProvider; var aspectRatio = 0.0; // 0.5625 double? height; @@ -62,6 +63,7 @@ class _StoryPlayerState extends State { @override void initState() { + videoSettingProvider = context.read(); super.initState(); updateRatio(); loadHiveInfo(); @@ -148,7 +150,6 @@ class _StoryPlayerState extends State { _betterPlayerController = BetterPlayerController(config); _betterPlayerController.setupDataSource(dataSource); }); - final videoSettingProvider = context.read(); if (videoSettingProvider.isMuted) { _betterPlayerController.setVolume(0.0); } @@ -158,7 +159,6 @@ class _StoryPlayerState extends State { } void _videoPlayerListener() { - final videoSettingProvider = context.read(); if (_betterPlayerController.videoPlayerController != null && _betterPlayerController.videoPlayerController!.value.initialized) { if (_betterPlayerController.videoPlayerController!.value.volume == 0.0 && diff --git a/pubspec.lock b/pubspec.lock index 8ef1d200..f0b1fe1e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: "1a52f1afae8ab7ac4741425114713bdbba802f1ce1e0648e167ffcc6e05e96cf" + sha256: "1639d96851f9e9e215dd39c9baad56846488aef3df392cb3221f37f70beac686" url: "https://pub.dev" source: hosted - version: "1.3.21" + version: "1.3.31" adaptive_action_sheet: dependency: "direct main" description: @@ -335,10 +335,10 @@ packages: dependency: transitive description: name: cross_file - sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" url: "https://pub.dev" source: hosted - version: "0.3.3+8" + version: "0.3.4+1" crypto: dependency: "direct main" description: @@ -511,34 +511,34 @@ packages: dependency: "direct main" description: name: firebase_analytics - sha256: edb9f9eaecf0e6431e5c12b7fabdb68be3e85ce51f941ccbfa6cb71327e8b535 + sha256: f3d82590042a5fc0470ea47d3350dc0f2ab12269437178f36e0e519d46992439 url: "https://pub.dev" source: hosted - version: "10.8.5" + version: "10.10.3" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - sha256: de4a54353cf58412c6da6b660a0dbad8efacb33b345c0286bc3a2edb869124d8 + sha256: "58ebb93af882c5290514e9157e90035c0ccf8e559a16c17331da7b3d6fb9e8f5" url: "https://pub.dev" source: hosted - version: "3.9.5" + version: "3.10.4" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - sha256: "77e4c02ffd0204ccc7856221193265c807b7e056fa62855f973a7f77435b5d41" + sha256: "578babefa09ddc92d088c08f5320cd160ef73b03e17fe1d95e43d90fed253b7f" url: "https://pub.dev" source: hosted - version: "0.5.5+17" + version: "0.5.7+3" firebase_core: dependency: "direct main" description: name: firebase_core - sha256: "7e049e32a9d347616edb39542cf92cd53fdb4a99fb6af0a0bff327c14cd76445" + sha256: "4aef2a23d0f3265545807d68fbc2f76a6b994ca3c778d88453b99325abd63284" url: "https://pub.dev" source: hosted - version: "2.25.4" + version: "2.30.1" firebase_core_platform_interface: dependency: transitive description: @@ -551,26 +551,26 @@ packages: dependency: transitive description: name: firebase_core_web - sha256: "57e61d6010e253b36d38191cefd6199d7849152cdcd234b61ca290cdb278a0ba" + sha256: "67f2fcc600fc78c2f731c370a3a5e6c87ee862e3a2fba6f951eca6d5dafe5c29" url: "https://pub.dev" source: hosted - version: "2.11.4" + version: "2.16.0" firebase_crashlytics: dependency: "direct main" description: name: firebase_crashlytics - sha256: efd096e4c3d2c568e128505b6e4ce5f5d5a1629f700a4d6fee6bd25b85937dde + sha256: b3e1eadbf37ec2062eba290f183db750f809ed6e7ffae8af9def67394645aec1 url: "https://pub.dev" source: hosted - version: "3.4.14" + version: "3.5.3" firebase_crashlytics_platform_interface: dependency: transitive description: name: firebase_crashlytics_platform_interface - sha256: "225a54d834a118be262c1f1096d407515e35b99d9b474c987abdcff7663f2b81" + sha256: e9a90f5c033fb77ed4dbebabf07aeb52502c581fca5fdc332edccc71f0557a47 url: "https://pub.dev" source: hosted - version: "3.6.21" + version: "3.6.31" fixnum: dependency: transitive description: @@ -1374,10 +1374,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" + sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.3.0" shared_preferences_windows: dependency: transitive description: @@ -1603,10 +1603,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b + sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.1" url_launcher_windows: dependency: transitive description: @@ -1771,10 +1771,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.5.1" web_socket_channel: dependency: "direct main" description: @@ -1848,5 +1848,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.3 <4.0.0" - flutter: ">=3.16.6" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index 8d72d5e0..bb2209d1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -90,9 +90,9 @@ dependencies: equatable: ^2.0.5 croppy: ^1.1.4 image: ^4.1.4 - firebase_core: ^2.25.4 - firebase_analytics: ^10.8.5 - firebase_crashlytics: ^3.4.14 + firebase_core: ^2.30.1 + firebase_analytics: ^10.10.3 + firebase_crashlytics: ^3.5.3 go_router: ^13.2.0 scrollable_positioned_list: ^0.3.8 From 85cedbe77efb7f80d68a9509b21d99b2f90e53b6 Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 25 Apr 2024 12:41:02 +0530 Subject: [PATCH 402/466] podcast episodes view --- .../podcast/trending_podcast_response.dart | 156 +++++----- .../widgets/new_feed_list_item.dart | 2 +- .../podcast_episodes_controller.dart | 47 +++ .../podcast/view/local_podcast_episode.dart | 23 +- .../podcast_episodes_appbar.dart | 75 +++++ .../podcast_episodes_view.dart | 264 +++++++++++++++++ .../screens/podcast/view/podcasts_feed.dart | 114 -------- .../widgets/audio_player/action_tools.dart | 8 +- .../new_pod_cast_epidose_player.dart | 272 +++++++++++------- .../podcast/widgets/podcast_feed_item.dart | 9 +- .../control_buttons.dart | 40 +-- .../podcast_player_slider.dart | 61 ++-- lib/src/widgets/cached_image.dart | 10 +- pubspec.lock | 40 +++ pubspec.yaml | 4 + 15 files changed, 781 insertions(+), 344 deletions(-) create mode 100644 lib/src/screens/podcast/controller/podcast_episodes_controller.dart create mode 100644 lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_appbar.dart create mode 100644 lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart delete mode 100644 lib/src/screens/podcast/view/podcasts_feed.dart diff --git a/lib/src/models/podcast/trending_podcast_response.dart b/lib/src/models/podcast/trending_podcast_response.dart index 029b4b68..cb1b626a 100644 --- a/lib/src/models/podcast/trending_podcast_response.dart +++ b/lib/src/models/podcast/trending_podcast_response.dart @@ -1,4 +1,3 @@ - import 'dart:convert'; import 'package:dart_rss/dart_rss.dart'; @@ -22,17 +21,25 @@ class TrendingPodCastResponse { this.description, }); - factory TrendingPodCastResponse.fromRawJson(String str) => TrendingPodCastResponse.fromJson(json.decode(str)); + factory TrendingPodCastResponse.fromRawJson(String str) => + TrendingPodCastResponse.fromJson(json.decode(str)); - factory TrendingPodCastResponse.fromJson(Map json) => TrendingPodCastResponse( - status: json["status"], - feeds: json["feeds"] == null ? [] : List.from(json["feeds"]!.map((x) => PodCastFeedItem.fromJson(x))), - items: json["items"] == null ? [] : List.from(json["items"]!.map((x) => PodCastFeedItem.fromJson(x))), - count: json["count"], - max: json["max"], - since: json["since"], - description: json["description"], - ); + factory TrendingPodCastResponse.fromJson(Map json) => + TrendingPodCastResponse( + status: json["status"], + feeds: json["feeds"] == null + ? [] + : List.from( + json["feeds"]!.map((x) => PodCastFeedItem.fromJson(x))), + items: json["items"] == null + ? [] + : List.from( + json["items"]!.map((x) => PodCastFeedItem.fromJson(x))), + count: json["count"], + max: json["max"], + since: json["since"], + description: json["description"], + ); } class PodCastFeedItem { @@ -44,11 +51,14 @@ class PodCastFeedItem { String? author; String? image; String? feedImage; + String? feedTitle; String? artwork; int? newestItemPublishTime; int? itunesId; int? trendScore; String? language; + String? feedLanguage; + String? datePublishedPretty; String? get networkImage { if (image != null && image!.isNotEmpty) { @@ -60,69 +70,77 @@ class PodCastFeedItem { return null; } - PodCastFeedItem({ - this.id, - this.url, - this.rssUrl, - this.title, - this.description, - this.author, - this.image, - this.feedImage, - this.artwork, - this.newestItemPublishTime, - this.itunesId, - this.trendScore, - this.language, - // this.categories, - }); + PodCastFeedItem( + {this.id, + this.url, + this.rssUrl, + this.title, + this.description, + this.author, + this.image, + this.feedImage, + this.artwork, + this.newestItemPublishTime, + this.itunesId, + this.trendScore, + this.language, + this.feedTitle, + this.feedLanguage, + this.datePublishedPretty + // this.categories, + }); - factory PodCastFeedItem.fromRawJson(String str) => PodCastFeedItem.fromJson(json.decode(str)); + factory PodCastFeedItem.fromRawJson(String str) => + PodCastFeedItem.fromJson(json.decode(str)); // String toRawJson() => json.encode(toJson()); - factory PodCastFeedItem.fromJson(Map json) => PodCastFeedItem( - id: json["id"].toString(), - url: json["url"], - title: json["title"], - rssUrl: json['rssUrl'], - description: json["description"], - author: json["author"], - image: json["image"], - feedImage: json["feedImage"], - artwork: json["artwork"], - newestItemPublishTime: json["newestItemPublishTime"], - itunesId: json["itunesId"], - trendScore: json["trendScore"], - language: json["language"], - // categories: json["categories"] != null ? Map.from(json["categories"]!).map((k, v) => MapEntry(k, v)) : null, - ); + factory PodCastFeedItem.fromJson(Map json) => + PodCastFeedItem( + id: json["id"].toString(), + url: json["url"], + title: json["title"], + rssUrl: json['rssUrl'], + description: json["description"], + author: json["author"], + image: json["image"], + feedImage: json["feedImage"], + feedTitle: json["feedTitle"], + feedLanguage: json["feedLanguage"], + artwork: json["artwork"], + newestItemPublishTime: json["newestItemPublishTime"], + itunesId: json["itunesId"], + trendScore: json["trendScore"], + language: json["language"], + datePublishedPretty: json["datePublishedPretty"], + // categories: json["categories"] != null ? Map.from(json["categories"]!).map((k, v) => MapEntry(k, v)) : null, + ); - factory PodCastFeedItem.fromRss(RssFeed rssFeed,String rssUrl) => PodCastFeedItem( - id:rssUrl, - rssUrl:rssUrl, - title: rssFeed.title, - description: rssFeed.description, - author: rssFeed.author, - image: rssFeed.image?.url, - feedImage: rssFeed.image?.url, - language: rssFeed.language - ); + factory PodCastFeedItem.fromRss(RssFeed rssFeed, String rssUrl) => + PodCastFeedItem( + id: rssUrl, + rssUrl: rssUrl, + title: rssFeed.title, + description: rssFeed.description, + author: rssFeed.author, + image: rssFeed.image?.url, + feedImage: rssFeed.image?.url, + language: rssFeed.language); Map toJson() => { - "id": id, - "url": url, - 'rssUrl':rssUrl, - "title": title, - "description": description, - "author": author, - "image": image, - "feedImage": feedImage, - "artwork": artwork, - "newestItemPublishTime": newestItemPublishTime, - "itunesId": itunesId, - "trendScore": trendScore, - "language": language, - // "categories": Map.from(categories!).map((k, v) => MapEntry(k, v)), - }; + "id": id, + "url": url, + 'rssUrl': rssUrl, + "title": title, + "description": description, + "author": author, + "image": image, + "feedImage": feedImage, + "artwork": artwork, + "newestItemPublishTime": newestItemPublishTime, + "itunesId": itunesId, + "trendScore": trendScore, + "language": language, + // "categories": Map.from(categories!).map((k, v) => MapEntry(k, v)), + }; } diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart index af79129d..8b7fc263 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/new_feed_list_item.dart @@ -458,7 +458,7 @@ class _NewFeedListItemState extends State return Positioned( bottom: 10, right: 10, - child: HomeFeedVideoTimer(totalDuration: widget.duration!), + child: HomeFeedVideoTimer(totalDuration: widget.duration ?? 0), ); } diff --git a/lib/src/screens/podcast/controller/podcast_episodes_controller.dart b/lib/src/screens/podcast/controller/podcast_episodes_controller.dart new file mode 100644 index 00000000..fd1a525f --- /dev/null +++ b/lib/src/screens/podcast/controller/podcast_episodes_controller.dart @@ -0,0 +1,47 @@ +import 'package:acela/src/models/podcast/podcast_episodes.dart'; +import 'package:acela/src/utils/enum.dart'; +import 'package:acela/src/utils/podcast/podcast_communicator.dart'; +import 'package:flutter/material.dart'; + +class PodcastEpisodesController extends ChangeNotifier { + List items = []; + ViewState viewState = ViewState.loading; + final bool isRss; + final String id; + + PodcastEpisodesController({required this.isRss, required this.id}) { + _init(); + } + + void _init() async { + try { + PodcastEpisodesByFeedResponse response = await fetchEpisodes(); + if (response.items != null && response.items!.isNotEmpty) { + items = response.items!; + viewState = ViewState.data; + } else { + viewState = ViewState.empty; + } + notifyListeners(); + } catch (e) { + viewState = ViewState.error; + notifyListeners(); + } + } + + Future fetchEpisodes() async { + if (isRss) { + return await PodCastCommunicator().getPodcastEpisodesByRss(id); + } else { + return await PodCastCommunicator().getPodcastEpisodesByFeedId(id); + } + } + + + + void refresh() { + viewState = ViewState.loading; + notifyListeners(); + _init(); + } +} diff --git a/lib/src/screens/podcast/view/local_podcast_episode.dart b/lib/src/screens/podcast/view/local_podcast_episode.dart index 1c804d77..78c8109f 100644 --- a/lib/src/screens/podcast/view/local_podcast_episode.dart +++ b/lib/src/screens/podcast/view/local_podcast_episode.dart @@ -119,22 +119,13 @@ class LocalEpisodeListView extends StatelessWidget { duration: Duration(seconds: item.duration ?? 0), ), ); - var screen = Scaffold( - appBar: AppBar( - title: ListTile( - leading: CachedImage( - imageUrl: item.image ?? '', - imageHeight: 40, - imageWidth: 40, - ), - title: Text(item.title ?? 'No Title'), - ), - ), - body: SafeArea( - child: NewPodcastEpidosePlayer( - podcastEpisodes: [item], - ), - ), + if (!GetAudioPlayer().audioHandler.isInitiated) { + GetAudioPlayer().audioHandler.isInitiated = true; + } + GetAudioPlayer().audioHandler.play(); + var screen = NewPodcastEpidosePlayer( + currentPodcastIndex: 0, + podcastEpisodes: [item], ); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); diff --git a/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_appbar.dart b/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_appbar.dart new file mode 100644 index 00000000..18eae9ed --- /dev/null +++ b/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_appbar.dart @@ -0,0 +1,75 @@ +import 'package:acela/src/widgets/cached_image.dart'; +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/material.dart'; + +class PodcastEpisodesAppbar extends StatefulWidget + implements PreferredSizeWidget { + final ScrollController scrollController; + final String? image; + final String? title; + + PodcastEpisodesAppbar({ + required this.scrollController, + required this.image, + required this.title, + }); + + @override + Size get preferredSize => Size.fromHeight(kToolbarHeight); + + @override + State createState() => _PodcastEpisodesAppbarState(); +} + +class _PodcastEpisodesAppbarState extends State { + ValueNotifier offset = ValueNotifier(0); + + @override + void initState() { + widget.scrollController.addListener(scrollListener); + super.initState(); + } + + @override + void dispose() { + widget.scrollController.removeListener(scrollListener); + super.dispose(); + } + + void scrollListener() { + offset.value = widget.scrollController.offset; + offset.value = widget.scrollController.offset; + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return AppBar( + backgroundColor: theme.primaryColorDark, + leadingWidth: 30, + title: ValueListenableBuilder( + valueListenable: offset, + builder: (context, value, child) { + return value > 130 + ? ListTile( + leading: CachedImage( + imageUrl: widget.image ?? '', + imageHeight: 35, + imageWidth: 35, + ), + title: AutoSizeText( + widget.title ?? 'No Title', + maxLines: 1, + maxFontSize: 14, + minFontSize: 12, + overflow: TextOverflow.ellipsis, + ), + ) + : Text( + "Podcast Episodes", + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ); + }), + ); + } +} diff --git a/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart b/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart new file mode 100644 index 00000000..9f2ce6b2 --- /dev/null +++ b/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart @@ -0,0 +1,264 @@ +import 'package:acela/src/models/podcast/podcast_episodes.dart'; +import 'package:acela/src/models/podcast/trending_podcast_response.dart'; +import 'package:acela/src/screens/podcast/controller/podcast_episodes_controller.dart'; +import 'package:acela/src/screens/podcast/view/podcast_episodes/podcast_episodes_appbar.dart'; +import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; +import 'package:acela/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart'; +import 'package:acela/src/utils/enum.dart'; +import 'package:acela/src/widgets/cached_image.dart'; +import 'package:acela/src/widgets/loading_screen.dart'; +import 'package:acela/src/widgets/retry.dart'; +import 'package:audio_service/audio_service.dart'; +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:provider/provider.dart'; + +class PodcastEpisodesView extends StatefulWidget { + const PodcastEpisodesView({Key? key, required this.feedItem}) + : super(key: key); + + final PodCastFeedItem feedItem; + + @override + State createState() => _PodcastEpisodesViewState(); +} + +class _PodcastEpisodesViewState extends State { + final ScrollController scrollController = ScrollController(); + + @override + void dispose() { + scrollController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return ChangeNotifierProvider( + create: (context) => PodcastEpisodesController( + isRss: widget.feedItem.rssUrl != null, + id: widget.feedItem.rssUrl != null + ? widget.feedItem.rssUrl! + : "${widget.feedItem.id ?? 227573}"), + builder: (context, child) { + final controller = context.read(); + return Scaffold( + appBar: PodcastEpisodesAppbar( + scrollController: scrollController, + title: widget.feedItem.title, + image: widget.feedItem.image, + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 15, + ), + child: Selector( + selector: (_, provider) => provider.viewState, + builder: (context, state, child) { + if (state == ViewState.data) { + return _data(controller.items, theme); + } else if (state == ViewState.empty) { + return RetryScreen( + error: "No episodes found", + onRetry: () => controller.refresh()); + } else if (state == ViewState.error) { + return RetryScreen( + error: "Something went wrong", + onRetry: () => controller.refresh()); + } else { + return LoadingScreen( + title: 'Loading', subtitle: 'Please wait..'); + } + }, + )), + ), + ); + }, + ); + } + + ListView _data(List episodes, ThemeData theme) { + return ListView.builder( + controller: scrollController, + itemCount: episodes.length, + itemBuilder: (context, index) { + PodcastEpisode item = episodes[index]; + print(item.duration.toString()); + return Column( + children: [ + if (index == 0) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + CachedImage( + imageHeight: 125, + imageWidth: 125, + borderRadius: 18, + imageUrl: widget.feedItem.networkImage), + SizedBox( + width: 15, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.feedItem.title ?? "", + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.bold), + ), + AutoSizeText( + widget.feedItem.author ?? "", + maxLines: 2, + maxFontSize: 13, + minFontSize: 11, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 13), + ), + ], + )) + ], + ), + if (widget.feedItem.description != null && + widget.feedItem.description!.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 20.0), + child: Text( + widget.feedItem.description ?? "", + maxLines: 3, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 13, fontWeight: FontWeight.w300), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 15), + child: FilledButton.icon( + onPressed: () async { + await _addEpisodesToQueue(episodes); + _initiatePlay(context, episodes, 0); + }, + style: FilledButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.all(Radius.circular(8))), + backgroundColor: theme.primaryColorLight), + label: Text( + "Play", + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 16), + ), + icon: Icon(Icons.play_arrow), + ), + ) + ], + ), + ), + ListTile( + onTap: () => onTapEpisode(index, context, episodes), + trailing: StreamBuilder( + stream: GetAudioPlayer().audioHandler.mediaItem, + builder: (context, snapshot) { + MediaItem? mediaItem = snapshot.data; + return mediaItem != null && + mediaItem.id == item.enclosureUrl + ? SizedBox( + height: 30, + width: 30, + child: SpinKitWave( + itemCount: 4, + type: SpinKitWaveType.center, + size: 15, + color: theme.primaryColorLight, + ), + ) + : Icon(Icons.play_circle_outline_outlined); + }), + leading: CachedImage( + imageUrl: item.image, + imageHeight: 48, + imageWidth: 48, + loadingIndicatorSize: 25, + ), + title: Text( + item.title!, + maxLines: 2, + style: TextStyle(fontSize: 13, fontWeight: FontWeight.w500), + ), + subtitle: item.duration != null || item.episode != null + ? Row( + children: [ + if (item.episode != null) + Text( + "#${item.episode} ${item.duration != null ? " • " : ""} ", + style: TextStyle(fontSize: 11), + ), + if (item.duration != null) + Text( + formatDuration(item.duration!), + style: TextStyle(fontSize: 11), + ), + ], + ) + : null, + ), + ], + ); + }, + ); + } + + void _initiatePlay( + BuildContext context, List episodes, int index) { + if (!GetAudioPlayer().audioHandler.isInitiated) { + GetAudioPlayer().audioHandler.isInitiated = true; + } + GetAudioPlayer().audioHandler.play(); + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => NewPodcastEpidosePlayer( + currentPodcastIndex: index, podcastEpisodes: episodes), + ), + ); + } + + void onTapEpisode( + int index, BuildContext context, List episodes) async { + await _addEpisodesToQueue(episodes); + GetAudioPlayer().audioHandler.skipToQueueItem(index); + _initiatePlay(context, episodes, index); + } + + String formatDuration(int seconds) { + Duration duration = Duration(seconds: seconds); + + if (duration.inHours < 1) { + return '${(duration.inMinutes % 60).toString().padLeft(2, '0')}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}'; + } else { + return '${duration.inHours}:${(duration.inMinutes % 60).toString().padLeft(2, '0')}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}'; + } + } + + Future _addEpisodesToQueue(List items) async { + GetAudioPlayer audioPlayer = GetAudioPlayer(); + await audioPlayer.audioHandler.updateQueue([]); + print(audioPlayer.audioHandler.queue.value.length); + await audioPlayer.audioHandler.addQueueItems(items + .map((e) => MediaItem( + id: e.enclosureUrl ?? "", + title: e.title ?? "", + artUri: Uri.parse(e.image ?? ""), + duration: Duration(seconds: e.duration ?? 0))) + .toList()); + } +} diff --git a/lib/src/screens/podcast/view/podcasts_feed.dart b/lib/src/screens/podcast/view/podcasts_feed.dart deleted file mode 100644 index 32f470b8..00000000 --- a/lib/src/screens/podcast/view/podcasts_feed.dart +++ /dev/null @@ -1,114 +0,0 @@ -import 'package:acela/src/models/podcast/podcast_episodes.dart'; -import 'package:acela/src/models/podcast/trending_podcast_response.dart'; -import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/utils/podcast/podcast_communicator.dart'; -import 'package:acela/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart'; -import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; -import 'package:acela/src/widgets/cached_image.dart'; -import 'package:acela/src/widgets/loading_screen.dart'; -import 'package:acela/src/widgets/retry.dart'; -import 'package:audio_service/audio_service.dart'; -import 'package:flutter/material.dart'; - -class PodcastFeedScreen extends StatefulWidget { - const PodcastFeedScreen({ - Key? key, - required this.appData, - required this.item, - }); - - final HiveUserData appData; - final PodCastFeedItem item; - - @override - State createState() => _PodcastFeedScreenState(); -} - -class _PodcastFeedScreenState extends State { - late Future future; - - @override - void initState() { - super.initState(); - if (!GetAudioPlayer().audioHandler.isInitiated) { - GetAudioPlayer().audioHandler.isInitiated = true; - GetAudioPlayer().audioHandler.play(); - } - - future = loadPodCastEpisode(); - } - - Widget _fullPost(List items) { - GetAudioPlayer audioPlayer = GetAudioPlayer(); - audioPlayer.audioHandler.updateQueue([]); - print(audioPlayer.audioHandler.queue.value.length); - audioPlayer.audioHandler.addQueueItems(items - .map((e) => MediaItem( - id: e.enclosureUrl ?? "", - title: e.title ?? "", - artUri: Uri.parse(e.image ?? ""), - duration: Duration(seconds: e.duration ?? 0))) - .toList()); - - return NewPodcastEpidosePlayer( - podcastEpisodes: items, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: ListTile( - leading: CachedImage( - imageUrl: widget.item.networkImage ?? '', - imageHeight: 40, - imageWidth: 40, - ), - title: Text(widget.item.title ?? 'No Title'), - ), - ), - body: SafeArea( - child: FutureBuilder( - future: future, - builder: (context, snapshot) { - if (snapshot.hasError) { - return RetryScreen( - error: snapshot.error.toString(), - onRetry: () { - setState(() { - future = loadPodCastEpisode(); - }); - }); - } else if (snapshot.connectionState == ConnectionState.done) { - var data = snapshot.data as PodcastEpisodesByFeedResponse; - var list = data.items ?? []; - if (list.isEmpty) { - return RetryScreen( - error: 'No data found.', - onRetry: () { - setState(() { - future = loadPodCastEpisode(); - }); - }); - } else { - return _fullPost(list); - } - } else { - return LoadingScreen(title: 'Loading', subtitle: 'Please wait..'); - } - }, - ), - ), - ); - } - - Future loadPodCastEpisode() { - if (widget.item.rssUrl != null) { - return PodCastCommunicator().getPodcastEpisodesByRss(widget.item.rssUrl!); - } else { - return PodCastCommunicator() - .getPodcastEpisodesByFeedId("${widget.item.id ?? 227573}"); - } - } -} diff --git a/lib/src/screens/podcast/widgets/audio_player/action_tools.dart b/lib/src/screens/podcast/widgets/audio_player/action_tools.dart index 02a6d78b..9c2e7f6a 100644 --- a/lib/src/screens/podcast/widgets/audio_player/action_tools.dart +++ b/lib/src/screens/podcast/widgets/audio_player/action_tools.dart @@ -50,6 +50,7 @@ class _SeekBarState extends State { @override Widget build(BuildContext context) { + final theme = Theme.of(context); final value = min( _dragValue ?? widget.position.inMilliseconds.toDouble(), widget.duration.inMilliseconds.toDouble(), @@ -62,8 +63,8 @@ class _SeekBarState extends State { SliderTheme( data: _sliderThemeData.copyWith( thumbShape: HiddenThumbComponentShape(), - activeTrackColor: Colors.blue.shade100, - inactiveTrackColor: Colors.grey.shade300, + // activeTrackColor: Colors.blue.shade100, + inactiveTrackColor: theme.primaryColorLight.withOpacity(0.5), ), child: ExcludeSemantics( child: Slider( @@ -78,6 +79,7 @@ class _SeekBarState extends State { SliderTheme( data: _sliderThemeData.copyWith( inactiveTrackColor: Colors.transparent, + thumbShape: RoundSliderThumbShape(enabledThumbRadius: 8.0), ), child: Slider( min: 0.0, @@ -475,4 +477,4 @@ void showSliderDialog({ ), ), ); -} \ No newline at end of file +} diff --git a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart index ff3463fe..28f52061 100644 --- a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart +++ b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:developer'; +import 'dart:ui'; import 'package:acela/src/models/podcast/podcast_episode_chapters.dart'; import 'package:acela/src/models/podcast/podcast_episodes.dart'; @@ -12,19 +13,26 @@ import 'package:acela/src/screens/podcast/widgets/podcast_info_description.dart' import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart'; +import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/cached_image.dart'; import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:marquee/marquee.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; import 'package:share_plus/share_plus.dart'; import 'package:video_player/video_player.dart'; class NewPodcastEpidosePlayer extends StatefulWidget { - const NewPodcastEpidosePlayer({Key? key, required this.podcastEpisodes}) + const NewPodcastEpidosePlayer( + {Key? key, + required this.podcastEpisodes, + required this.currentPodcastIndex}) : super(key: key); final List podcastEpisodes; + final int currentPodcastIndex; @override State createState() => @@ -62,6 +70,7 @@ class _NewPodcastEpidosePlayerState extends State { @override void initState() { super.initState(); + currentPodcastIndex = widget.currentPodcastIndex; currentPodcastEpisode = widget.podcastEpisodes[currentPodcastIndex]; log(currentPodcastEpisode.enclosureUrl!); _setUpVideo(); @@ -137,101 +146,169 @@ class _NewPodcastEpidosePlayerState extends State { @override Widget build(BuildContext context) { + final screenWidth = MediaQuery.of(context).size.width; + final theme = Theme.of(context); return ChangeNotifierProvider.value( value: chapterController, child: Scaffold( body: SafeArea( - child: StreamBuilder( - stream: _audioHandler.mediaItem, - builder: (context, snapshot) { - final mediaItem = snapshot.data; - if (mediaItem == null) return const SizedBox(); - return Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _audioHandler.shouldPlayVideo() - ? SizedBox( - height: MediaQuery.of(context).size.height * 0.45, - child: Center( - child: ValueListenableBuilder( - valueListenable: _audioHandler.aspectRatioNotifier, - builder: (context, aspectRatio, child) { - return AspectRatio( - aspectRatio: aspectRatio ?? 1.5, - child: child); - }, - child: VideoPlayer( - _audioHandler.videoPlayerController!), - )), - ) - : Container( - constraints: BoxConstraints( - maxHeight: - MediaQuery.of(context).size.height * 0.45), - child: Selector( - selector: (_, myType) => myType.image, - builder: (context, chapterImage, child) { - return CachedImage( - imageUrl: chapterImage ?? originalImage, - imageHeight: - MediaQuery.of(context).size.height * 0.45, - ); - }, - )), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10), - child: Column( - children: [ - Selector( - selector: (_, myType) => myType.title, - builder: (context, chapterTitle, child) { - return Text( - chapterTitle ?? originalTitle, - textAlign: TextAlign.center, - maxLines: 3, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.titleLarge, - ); - }, - ), - const SizedBox( - height: 5, - ), - Text( - currentPodcastEpisode.datePublishedPretty.toString(), - style: TextStyle(fontSize: 12), - ), - ], + child: Stack( + fit: StackFit.expand, + children: [ + if (originalImage != null && originalImage!.isNotEmpty) + CachedImage( + imageUrl: originalImage, + ), + if (originalImage != null && originalImage!.isNotEmpty) + Positioned.fill( + child: ClipRRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 40, sigmaY: 40), + child: const SizedBox.shrink(), ), ), - userToolbar(), - PodcastPlayerSlider( - episode: currentPodcastEpisode, - chapterController: chapterController, - audioPlayerHandler: _audioHandler, - positionDataStream: _positionDataStream, - currentPodcastEpisodeDuration: - currentPodcastEpisode.duration), - ControlButtons( - _audioHandler, - chapterController: chapterController, - podcastEpisode: currentPodcastEpisode, - showSkipPreviousButtom: widget.podcastEpisodes.length > 1, - positionStream: _positionDataStream.asBroadcastStream(), - ), - ], - ); - }, + ), + Positioned.fill( + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + theme.primaryColorDark, + theme.primaryColorDark.withOpacity(0.3) + ])), + )), + StreamBuilder( + stream: _audioHandler.mediaItem, + builder: (context, snapshot) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Spacer(), + _audioHandler.shouldPlayVideo() + ? SizedBox( + height: MediaQuery.of(context).size.height * 0.45, + child: Center( + child: ValueListenableBuilder( + valueListenable: + _audioHandler.aspectRatioNotifier, + builder: (context, aspectRatio, child) { + return AspectRatio( + aspectRatio: aspectRatio ?? 1.5, + child: child); + }, + child: VideoPlayer( + _audioHandler.videoPlayerController!), + )), + ) + : Container( + margin: EdgeInsets.symmetric(horizontal: 30), + constraints: BoxConstraints( + maxHeight: + MediaQuery.of(context).size.height * + 0.45), + child: + Selector( + selector: (_, myType) => myType.image, + builder: (context, chapterImage, child) { + return CachedImage( + imageUrl: chapterImage ?? originalImage, + imageHeight: + MediaQuery.of(context).size.height * + 0.45, + ); + }, + )), + Spacer(), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 15.0, horizontal: 10), + child: Column( + children: [ + _title(screenWidth), + const SizedBox( + height: 5, + ), + Text( + currentPodcastEpisode.datePublishedPretty + .toString(), + style: TextStyle(fontSize: 12), + ), + ], + ), + ), + userToolbar(theme), + PodcastPlayerSlider( + episode: currentPodcastEpisode, + chapterController: chapterController, + audioPlayerHandler: _audioHandler, + positionDataStream: _positionDataStream, + currentPodcastEpisodeDuration: + currentPodcastEpisode.duration), + Gap(10), + ControlButtons( + _audioHandler, + chapterController: chapterController, + podcastEpisode: currentPodcastEpisode, + showSkipPreviousButtom: + widget.podcastEpisodes.length > 1, + positionStream: _positionDataStream.asBroadcastStream(), + ), + Spacer(), + ], + ); + }, + ), + ], ), ), ), ); } - Widget userToolbar() { - Color iconColor = Colors.lightBlue; + Selector _title(double screenWidth) { + return Selector( + selector: (_, myType) => myType.title, + builder: (context, chapterTitle, child) { + return SizedBox( + width: screenWidth * 0.85, + height: 25, + child: Utilities.textLines( + chapterTitle ?? originalTitle, + TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + screenWidth * 0.85, + 3) > + 1 + ? Marquee( + text: chapterTitle ?? originalTitle, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + scrollAxis: Axis.horizontal, + crossAxisAlignment: CrossAxisAlignment.start, + blankSpace: 50, + velocity: 40.0, + pauseAfterRound: const Duration(milliseconds: 1000), + showFadingOnlyWhenScrolling: true, + fadingEdgeStartFraction: 0.1, + fadingEdgeEndFraction: 0.1, + startPadding: 0.0, + accelerationDuration: const Duration(seconds: 2), + accelerationCurve: Curves.linear, + decelerationDuration: const Duration(milliseconds: 500), + decelerationCurve: Curves.easeOut, + ) + : Text( + chapterTitle ?? originalTitle, + textAlign: TextAlign.center, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + ), + ); + }, + ); + } + + Widget userToolbar(ThemeData theme) { + Color iconColor = theme.primaryColorLight; List tools = [ IconButton( constraints: const BoxConstraints(), @@ -254,19 +331,20 @@ class _NewPodcastEpidosePlayerState extends State { episode: currentPodcastEpisode, ), FavouriteWidget( - toastType: "Podcast Episode", - disablePadding: true, - iconColor: iconColor, - isLiked: podcastController - .isLikedPodcastEpisodePresentLocally(currentPodcastEpisode), - onAdd: () { - podcastController - .storeLikedPodcastEpisodeLocally(currentPodcastEpisode); - }, - onRemove: () { - podcastController - .storeLikedPodcastEpisodeLocally(currentPodcastEpisode); - }), + toastType: "Podcast Episode", + disablePadding: true, + iconColor: iconColor, + isLiked: podcastController + .isLikedPodcastEpisodePresentLocally(currentPodcastEpisode), + onAdd: () { + podcastController + .storeLikedPodcastEpisodeLocally(currentPodcastEpisode); + }, + onRemove: () { + podcastController + .storeLikedPodcastEpisodeLocally(currentPodcastEpisode); + }, + ), IconButton( onPressed: () { _onTapPodcastHistory(); diff --git a/lib/src/screens/podcast/widgets/podcast_feed_item.dart b/lib/src/screens/podcast/widgets/podcast_feed_item.dart index 63abab83..77288a2a 100644 --- a/lib/src/screens/podcast/widgets/podcast_feed_item.dart +++ b/lib/src/screens/podcast/widgets/podcast_feed_item.dart @@ -1,7 +1,7 @@ import 'package:acela/src/models/podcast/trending_podcast_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; -import 'package:acela/src/screens/podcast/view/podcasts_feed.dart'; +import 'package:acela/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart'; import 'package:acela/src/screens/podcast/widgets/favourite.dart'; import 'package:acela/src/widgets/cached_image.dart'; import 'package:flutter/material.dart'; @@ -43,7 +43,7 @@ class _PodcastFeedItemWidgetState extends State { trailing: Visibility( visible: widget.showLikeButton, child: FavouriteWidget( - toastType: "Podcast", + toastType: "Podcast", isLiked: podcastController.isLikedPodcastPresentLocally(widget.item), onAdd: () { @@ -54,8 +54,9 @@ class _PodcastFeedItemWidgetState extends State { }), ), onTap: () { - var screen = - PodcastFeedScreen(appData: widget.appData, item: widget.item); + // var screen = + // PodcastFeedScreen(appData: widget.appData, item: widget.item); + var screen = PodcastEpisodesView(feedItem: widget.item); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); }, diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart index 92f8b3c8..72b8320b 100644 --- a/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart @@ -26,8 +26,9 @@ class ControlButtons extends StatelessWidget { @override Widget build(BuildContext context) { + final theme = Theme.of(context); bool isPaused = false; - Color iconColor = Colors.white; + Color iconColor = theme.primaryColorLight; return Row( mainAxisSize: MainAxisSize.min, children: [ @@ -60,7 +61,7 @@ class ControlButtons extends StatelessWidget { final positionData = snapshot.data ?? PositionData(Duration.zero, Duration.zero, Duration.zero); return PodcastPlayerInteractionIconButton( - size: 30, + size: 35, horizontalPadding: 20, onPressed: () => goBackTenSeconds(positionData), icon: Icons.replay_10, @@ -77,41 +78,40 @@ class ControlButtons extends StatelessWidget { audioHandler.play(); if (processingState == AudioProcessingState.loading || processingState == AudioProcessingState.buffering) { - return SizedBox( - width: 40.0, - height: 40.0, - child: const CircularProgressIndicator( + return CircleAvatar( + radius: 32, + backgroundColor: theme.primaryColorLight, + child: CircularProgressIndicator( strokeWidth: 2.5, + color: theme.primaryColorDark, ), ); } else if (playing != true) { return GestureDetector( onTap: audioHandler.play, - child: SizedBox( - height: 40, - width: 40, - child: CircleAvatar( - backgroundColor: Colors.white, - child: Icon( - Icons.play_arrow, - size: 30, - color: Colors.black, - ), + child: CircleAvatar( + radius: 32, + backgroundColor: theme.primaryColorLight, + child: Icon( + Icons.play_arrow, + size: 35, + color: Colors.black, ), ), ); } else { - _continueFromDuration(context); + _continueFromDuration(context); return GestureDetector( onTap: () { isPaused = !isPaused; audioHandler.pause(); }, child: CircleAvatar( - backgroundColor: Colors.white, + radius: 32, + backgroundColor: theme.primaryColorLight, child: Icon( Icons.pause, - size: 30, + size: 35, color: Colors.black, ), ), @@ -125,7 +125,7 @@ class ControlButtons extends StatelessWidget { final positionData = snapshot.data ?? PositionData(Duration.zero, Duration.zero, Duration.zero); return PodcastPlayerInteractionIconButton( - size: 30, + size: 35, horizontalPadding: 20, onPressed: () => _goForwardTenSeconds(positionData), icon: Icons.forward_10, diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart index 077ee7ec..da61c3a9 100644 --- a/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart @@ -5,8 +5,8 @@ import 'package:acela/src/screens/podcast/controller/podcast_chapters_controller import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; import 'package:acela/src/screens/podcast/widgets/audio_player/action_tools.dart'; import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; -import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:provider/provider.dart'; class PodcastPlayerSlider extends StatelessWidget { @@ -28,7 +28,7 @@ class PodcastPlayerSlider extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.only(left: 15, right: 15, bottom: 5), + padding: const EdgeInsets.symmetric(vertical: 10), child: StreamBuilder( stream: positionDataStream, builder: (context, snapshot) { @@ -37,25 +37,42 @@ class PodcastPlayerSlider extends StatelessWidget { // writeCurrentDurationLocal(context, positionData.position.inSeconds); var duration = currentPodcastEpisodeDuration?.toDouble() ?? 0.0; var pending = duration - positionData.position.inSeconds; - var pendingText = "${Utilities.formatTime(pending.toInt())}"; - var leadingText = - "${Utilities.formatTime(positionData.position.inSeconds)}"; + var pendingText = formatDuration(pending.toInt()); + var leadingText = formatDuration(positionData.position.inSeconds); chapterController.setDurationData(positionData); chapterController.syncChapters(); - return Row( + return Column( children: [ - Text(leadingText), - Expanded( - child: SeekBar( - duration: positionData.duration, - position: positionData.position, - onChanged: _onSlideChange, - onChangeEnd: (newPosition) { - audioPlayerHandler.seek(newPosition); - }, - ), + Stack( + clipBehavior: Clip.none, + children: [ + SeekBar( + duration: positionData.duration, + position: positionData.position, + onChanged: _onSlideChange, + onChangeEnd: (newPosition) { + audioPlayerHandler.seek(newPosition); + }, + ), + Positioned( + bottom: -8, + left: 0, + right: 0, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 22.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + leadingText, + style: TextStyle(fontSize: 12), + ), + Text(pendingText, style: TextStyle(fontSize: 12)), + ], + ), + )) + ], ), - Text(pendingText), ], ); }, @@ -63,6 +80,16 @@ class PodcastPlayerSlider extends StatelessWidget { ); } + String formatDuration(int seconds) { + Duration duration = Duration(seconds: seconds); + + if (duration.inHours < 1) { + return '${(duration.inMinutes % 60).toString().padLeft(2, '0')}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}'; + } else { + return '${duration.inHours}:${(duration.inMinutes % 60).toString().padLeft(2, '0')}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}'; + } + } + void writeCurrentDurationLocal(BuildContext context, int seconds) { Future.delayed(Duration(seconds: 10)).then((value) { if (seconds > 0) { diff --git a/lib/src/widgets/cached_image.dart b/lib/src/widgets/cached_image.dart index 9655ee22..420071f8 100644 --- a/lib/src/widgets/cached_image.dart +++ b/lib/src/widgets/cached_image.dart @@ -8,6 +8,7 @@ class CachedImage extends StatelessWidget { this.imageHeight, this.imageWidth, this.loadingIndicatorSize, + this.borderRadius, this.fit}) : super(key: key); @@ -16,13 +17,16 @@ class CachedImage extends StatelessWidget { final double? imageWidth; final double? loadingIndicatorSize; final BoxFit? fit; + final double? borderRadius; @override Widget build(BuildContext context) { return Container( - color: Theme.of(context).primaryColorLight == Colors.black - ? Colors.grey.shade400 - : Colors.grey.shade900, + decoration: BoxDecoration( + color: Theme.of(context).primaryColorLight == Colors.black + ? Colors.grey.shade400 + : Colors.grey.shade900, + borderRadius: BorderRadius.all(Radius.circular(borderRadius ?? 0))), child: CachedNetworkImage( imageUrl: imageUrl ?? '', height: imageHeight, diff --git a/pubspec.lock b/pubspec.lock index f0b1fe1e..e35af9f2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -114,6 +114,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.18" + auto_size_text: + dependency: "direct main" + description: + name: auto_size_text + sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" + url: "https://pub.dev" + source: hosted + version: "3.0.0" base_x: dependency: transitive description: @@ -427,6 +435,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.5" + fading_edge_scrollview: + dependency: transitive + description: + name: fading_edge_scrollview + sha256: c25c2231652ce774cc31824d0112f11f653881f43d7f5302c05af11942052031 + url: "https://pub.dev" + source: hosted + version: "3.0.0" fake_async: dependency: transitive description: @@ -680,6 +696,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + flutter_spinkit: + dependency: "direct main" + description: + name: flutter_spinkit + sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472 + url: "https://pub.dev" + source: hosted + version: "5.2.1" flutter_test: dependency: "direct dev" description: flutter @@ -722,6 +746,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.23.8" + gap: + dependency: "direct main" + description: + name: gap + sha256: f19387d4e32f849394758b91377f9153a1b41d79513ef7668c088c77dbc6955d + url: "https://pub.dev" + source: hosted + version: "3.0.1" get: dependency: transitive description: @@ -1010,6 +1042,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.2.1" + marquee: + dependency: "direct main" + description: + name: marquee + sha256: "4b5243d2804373bdc25fc93d42c3b402d6ec1f4ee8d0bb72276edd04ae7addb8" + url: "https://pub.dev" + source: hosted + version: "2.2.3" matcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bb2209d1..5b6c8b47 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -95,6 +95,10 @@ dependencies: firebase_crashlytics: ^3.5.3 go_router: ^13.2.0 scrollable_positioned_list: ^0.3.8 + auto_size_text: ^3.0.0 + gap: ^3.0.1 + marquee: ^2.2.3 + flutter_spinkit: ^5.2.1 dev_dependencies: flutter_test: From 73cf0665270216d99598d9758dbdc1b26f871c16 Mon Sep 17 00:00:00 2001 From: Sagar Date: Mon, 29 Apr 2024 20:35:04 +0530 Subject: [PATCH 403/466] miniplayer in podcast --- lib/main.dart | 4 + .../screens/favourites/user_favourites.dart | 11 +- .../controller/podcast_controller.dart | 8 + .../controller/podcast_player_controller.dart | 71 ++++ .../screens/podcast/view/liked_podcasts.dart | 36 +- .../podcast/view/local_podcast_episode.dart | 60 ++-- .../podcast_episodes_view.dart | 282 +++++++--------- .../podcast/view/podcast_trending.dart | 183 ++++++---- .../new_pod_cast_epidose_player.dart | 318 ++++++++++++------ .../podcast/widgets/podcast_feed_item.dart | 11 +- .../control_buttons.dart | 134 +++++--- .../podcast_player_slider.dart | 2 +- .../podcast_player_widgets/progress_bar.dart | 51 +++ pubspec.lock | 8 + pubspec.yaml | 1 + 15 files changed, 735 insertions(+), 445 deletions(-) create mode 100644 lib/src/screens/podcast/controller/podcast_player_controller.dart create mode 100644 lib/src/screens/podcast/widgets/podcast_player_widgets/progress_bar.dart diff --git a/lib/main.dart b/lib/main.dart index cf9d724b..a994e82d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,6 +4,7 @@ import 'package:acela/src/global_provider/image_resolution_provider.dart'; import 'package:acela/src/global_provider/video_setting_provider.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; +import 'package:acela/src/screens/podcast/controller/podcast_player_controller.dart'; import 'package:acela/src/screens/upload/video/controller/video_upload_controller.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; import 'package:acela/src/utils/routes/app_router.dart'; @@ -116,6 +117,9 @@ class _MyAppState extends State { lazy: false, create: (context) => SettingsProvider(), ), + ChangeNotifierProvider( + create: (context) => PodcastPlayerController(), + ), ChangeNotifierProvider(create: (context) => VideoUploadController()) ], child: OverlaySupport.global( diff --git a/lib/src/screens/favourites/user_favourites.dart b/lib/src/screens/favourites/user_favourites.dart index 9ea3c7bb..9f75846e 100644 --- a/lib/src/screens/favourites/user_favourites.dart +++ b/lib/src/screens/favourites/user_favourites.dart @@ -69,11 +69,18 @@ class _UserFavouritesState extends State FavouriteTagsBody(), FavouriteUsersBody(), LikedPodcasts( + playOnMiniPlayer: false, appData: appData, showAppBar: false, ), - LocalEpisodeListView(isOffline: false), - LocalEpisodeListView(isOffline: true), + LocalEpisodeListView( + isOffline: false, + playOnMiniPlayer: false, + ), + LocalEpisodeListView( + isOffline: true, + playOnMiniPlayer: false, + ), ]), ); } diff --git a/lib/src/screens/podcast/controller/podcast_controller.dart b/lib/src/screens/podcast/controller/podcast_controller.dart index 42ab36b6..0cd1a405 100644 --- a/lib/src/screens/podcast/controller/podcast_controller.dart +++ b/lib/src/screens/podcast/controller/podcast_controller.dart @@ -192,6 +192,14 @@ class PodcastController extends ChangeNotifier { List json = box.read(key); List items = json.map((e) => PodcastEpisode.fromJson(e)).toList(); + if (isOffline) { + items = items.map((e) { + String url = e.enclosureUrl ?? ""; + url = Uri.parse(getOfflineUrl(e.enclosureUrl ?? "", e.id!)).path; + e.enclosureUrl = '$url'; + return e; + }).toList(); + } return items; } else { return []; diff --git a/lib/src/screens/podcast/controller/podcast_player_controller.dart b/lib/src/screens/podcast/controller/podcast_player_controller.dart new file mode 100644 index 00000000..333823eb --- /dev/null +++ b/lib/src/screens/podcast/controller/podcast_player_controller.dart @@ -0,0 +1,71 @@ +import 'package:acela/src/models/podcast/podcast_episodes.dart'; +import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; +import 'package:acela/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart'; +import 'package:audio_service/audio_service.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:miniplayer/miniplayer.dart'; + +class PodcastPlayerController extends ChangeNotifier { + final MiniplayerController miniplayerController = MiniplayerController(); + List episodes = []; + int index = 0; + + void openPodcastPlayer(int index, {bool playOnMiniPlayer = true}) { + this.index = index; + notifyListeners(); + if (playOnMiniPlayer) { + miniplayerController.animateToHeight(state: PanelState.MAX); + } + } + + void setData(List episodes, int index, + {bool playOnMiniPlayer = true}) { + this.episodes = episodes; + openPodcastPlayer(index, playOnMiniPlayer: playOnMiniPlayer); + } + + Future _addEpisodesToQueue(List items) async { + GetAudioPlayer audioPlayer = GetAudioPlayer(); + await audioPlayer.audioHandler.updateQueue([]); + print(audioPlayer.audioHandler.queue.value.length); + await audioPlayer.audioHandler.addQueueItems(items + .map((e) => MediaItem( + id: e.enclosureUrl ?? "", + title: e.title ?? "", + artUri: Uri.parse(e.image ?? ""), + duration: Duration(seconds: e.duration ?? 0))) + .toList()); + } + + void _initiatePlay(BuildContext context, List episodes, + int index, bool playOnMiniPlayer) { + if (!GetAudioPlayer().audioHandler.isInitiated) { + GetAudioPlayer().audioHandler.isInitiated = true; + } + GetAudioPlayer().audioHandler.play(); + setData(episodes, index, playOnMiniPlayer: playOnMiniPlayer); + if (!playOnMiniPlayer) { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => NewPodcastEpidosePlayer( + dragValue: 1, + currentPodcastIndex: index, + podcastEpisodes: episodes), + ), + ); + } + } + + void onTapEpisode(int index, BuildContext context, + List episodes, bool playOnMiniPlayer) async { + await _addEpisodesToQueue(episodes); + GetAudioPlayer().audioHandler.skipToQueueItem(index); + _initiatePlay(context, episodes, index, playOnMiniPlayer); + } + + void onDefaultPlay(BuildContext context, bool playOnMiniPlayer) async { + await _addEpisodesToQueue(episodes); + _initiatePlay(context, episodes, 0, playOnMiniPlayer); + } +} diff --git a/lib/src/screens/podcast/view/liked_podcasts.dart b/lib/src/screens/podcast/view/liked_podcasts.dart index 4e6cc526..ebecf29a 100644 --- a/lib/src/screens/podcast/view/liked_podcasts.dart +++ b/lib/src/screens/podcast/view/liked_podcasts.dart @@ -10,11 +10,13 @@ class LikedPodcasts extends StatefulWidget { {Key? key, required this.appData, this.showAppBar = true, + this.playOnMiniPlayer = true, this.filterOnlyRssPodcasts = false}) : super(key: key); final HiveUserData appData; final bool showAppBar; + final bool playOnMiniPlayer; final bool filterOnlyRssPodcasts; @override @@ -34,24 +36,28 @@ class _LikedPodcastsState extends State { ) : null, body: items.isEmpty - ? Center(child: Text(widget.filterOnlyRssPodcasts ? "" : "Liked Podcasts is Empty")) + ? Center( + child: Text(widget.filterOnlyRssPodcasts + ? "" + : "Liked Podcasts is Empty")) : ListView.separated( itemBuilder: (c, i) { return Dismissible( - key: Key(items[i].id!), - background: Center(child: Text("Delete")), - onDismissed: (direction) { - context - .read() - .storeLikedPodcastLocally(items[i]); - showSnackBar("Podcast ${items[i].title} is removed"); - }, - child: PodcastFeedItemWidget( - showLikeButton: false, - appData: widget.appData, - item: items[i], - ), - ); + key: Key(items[i].id!), + background: Center(child: Text("Delete")), + onDismissed: (direction) { + context + .read() + .storeLikedPodcastLocally(items[i]); + showSnackBar("Podcast ${items[i].title} is removed"); + }, + child: PodcastFeedItemWidget( + playOnMiniPlayer: widget.playOnMiniPlayer, + showLikeButton: false, + appData: widget.appData, + item: items[i], + ), + ); }, separatorBuilder: (c, i) => const Divider(height: 0), itemCount: items.length, diff --git a/lib/src/screens/podcast/view/local_podcast_episode.dart b/lib/src/screens/podcast/view/local_podcast_episode.dart index 78c8109f..8a55e005 100644 --- a/lib/src/screens/podcast/view/local_podcast_episode.dart +++ b/lib/src/screens/podcast/view/local_podcast_episode.dart @@ -4,18 +4,17 @@ import 'dart:io'; import 'package:acela/src/models/podcast/podcast_episodes.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; -import 'package:acela/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart'; -import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; -import 'package:acela/src/widgets/cached_image.dart'; +import 'package:acela/src/screens/podcast/controller/podcast_player_controller.dart'; import 'package:acela/src/widgets/confirmation_dialog.dart'; -import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class LocalPodcastEpisode extends StatelessWidget { - const LocalPodcastEpisode({Key? key, required this.appData}) + const LocalPodcastEpisode( + {Key? key, required this.appData, this.playOnMiniPlayer = true}) : super(key: key); final HiveUserData appData; + final bool playOnMiniPlayer; @override Widget build(BuildContext context) { @@ -33,8 +32,14 @@ class LocalPodcastEpisode extends StatelessWidget { ), body: TabBarView( children: [ - LocalEpisodeListView(isOffline: true), - LocalEpisodeListView(isOffline: false), + LocalEpisodeListView( + isOffline: true, + playOnMiniPlayer: playOnMiniPlayer, + ), + LocalEpisodeListView( + isOffline: false, + playOnMiniPlayer: playOnMiniPlayer, + ), ], ), ), @@ -43,10 +48,12 @@ class LocalPodcastEpisode extends StatelessWidget { } class LocalEpisodeListView extends StatelessWidget { - const LocalEpisodeListView({Key? key, required this.isOffline}) + const LocalEpisodeListView( + {Key? key, required this.isOffline, required this.playOnMiniPlayer}) : super(key: key); final bool isOffline; + final bool playOnMiniPlayer; @override Widget build(BuildContext context) { @@ -91,44 +98,21 @@ class LocalEpisodeListView extends StatelessWidget { forceRemove: true); } }, - child: podcastEpisodeListItem(item, context, controller)); + child: podcastEpisodeListItem(items, context, controller, index)); }, separatorBuilder: (c, i) => const Divider(height: 0), itemCount: items.length, ); } - ListTile podcastEpisodeListItem( - PodcastEpisode item, BuildContext context, PodcastController controller) { - String url = item.enclosureUrl ?? ""; - if (isOffline) { - url = - Uri.parse(controller.getOfflineUrl(item.enclosureUrl ?? "", item.id!)) - .path; - item.enclosureUrl = '$url'; - } + ListTile podcastEpisodeListItem(List items, + BuildContext context, PodcastController controller, int index) { + PodcastEpisode item = items[index]; return ListTile( onTap: () { - GetAudioPlayer audioPlayer = GetAudioPlayer(); - audioPlayer.audioHandler.updateQueue([]); - audioPlayer.audioHandler.addQueueItem( - MediaItem( - id: url, - title: item.title ?? "", - artUri: Uri.parse(item.image ?? ""), - duration: Duration(seconds: item.duration ?? 0), - ), - ); - if (!GetAudioPlayer().audioHandler.isInitiated) { - GetAudioPlayer().audioHandler.isInitiated = true; - } - GetAudioPlayer().audioHandler.play(); - var screen = NewPodcastEpidosePlayer( - currentPodcastIndex: 0, - podcastEpisodes: [item], - ); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); + final playerController = context.read(); + playerController.onTapEpisode( + index, context, items, playOnMiniPlayer); }, leading: Container( height: 30, diff --git a/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart b/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart index 9f2ce6b2..d900b1ad 100644 --- a/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart +++ b/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart @@ -1,9 +1,9 @@ import 'package:acela/src/models/podcast/podcast_episodes.dart'; import 'package:acela/src/models/podcast/trending_podcast_response.dart'; import 'package:acela/src/screens/podcast/controller/podcast_episodes_controller.dart'; +import 'package:acela/src/screens/podcast/controller/podcast_player_controller.dart'; import 'package:acela/src/screens/podcast/view/podcast_episodes/podcast_episodes_appbar.dart'; import 'package:acela/src/screens/podcast/widgets/audio_player/audio_player_core_controls.dart'; -import 'package:acela/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart'; import 'package:acela/src/utils/enum.dart'; import 'package:acela/src/widgets/cached_image.dart'; import 'package:acela/src/widgets/loading_screen.dart'; @@ -15,10 +15,12 @@ import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:provider/provider.dart'; class PodcastEpisodesView extends StatefulWidget { - const PodcastEpisodesView({Key? key, required this.feedItem}) + const PodcastEpisodesView( + {Key? key, required this.feedItem, required this.playOnMiniPlayer}) : super(key: key); final PodCastFeedItem feedItem; + final bool playOnMiniPlayer; @override State createState() => _PodcastEpisodesViewState(); @@ -60,7 +62,7 @@ class _PodcastEpisodesViewState extends State { selector: (_, provider) => provider.viewState, builder: (context, state, child) { if (state == ViewState.data) { - return _data(controller.items, theme); + return _data(controller.items, theme, context); } else if (state == ViewState.empty) { return RetryScreen( error: "No episodes found", @@ -81,164 +83,139 @@ class _PodcastEpisodesViewState extends State { ); } - ListView _data(List episodes, ThemeData theme) { + ListView _data( + List episodes, ThemeData theme, BuildContext context) { + final PodcastPlayerController playerController = + context.read(); return ListView.builder( controller: scrollController, itemCount: episodes.length, itemBuilder: (context, index) { PodcastEpisode item = episodes[index]; - print(item.duration.toString()); - return Column( - children: [ - if (index == 0) - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 15, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Row( - children: [ - CachedImage( - imageHeight: 125, - imageWidth: 125, - borderRadius: 18, - imageUrl: widget.feedItem.networkImage), - SizedBox( - width: 15, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.feedItem.title ?? "", - style: TextStyle( - fontSize: 20, fontWeight: FontWeight.bold), - ), - AutoSizeText( - widget.feedItem.author ?? "", - maxLines: 2, - maxFontSize: 13, - minFontSize: 11, - overflow: TextOverflow.ellipsis, - style: TextStyle(fontSize: 13), - ), - ], - )) - ], - ), - if (widget.feedItem.description != null && - widget.feedItem.description!.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 20.0), - child: Text( - widget.feedItem.description ?? "", - maxLines: 3, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 13, fontWeight: FontWeight.w300), - ), + return Padding( + padding: + EdgeInsets.only(bottom: index == episodes.length - 1 ? 65.0 : 0), + child: Column( + children: [ + if (index == 0) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + CachedImage( + imageHeight: 125, + imageWidth: 125, + borderRadius: 18, + imageUrl: widget.feedItem.networkImage), + SizedBox( + width: 15, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AutoSizeText( + widget.feedItem.title ?? "", + maxLines: 5, + minFontSize: 13, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.bold), + ), + AutoSizeText( + widget.feedItem.author ?? "", + maxLines: 2, + maxFontSize: 13, + minFontSize: 11, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 13), + ), + ], + )) + ], ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 15), - child: FilledButton.icon( - onPressed: () async { - await _addEpisodesToQueue(episodes); - _initiatePlay(context, episodes, 0); - }, - style: FilledButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.all(Radius.circular(8))), - backgroundColor: theme.primaryColorLight), - label: Text( - "Play", - style: TextStyle( - fontWeight: FontWeight.bold, fontSize: 16), + Padding( + padding: const EdgeInsets.symmetric(vertical: 15), + child: FilledButton.icon( + onPressed: () => playerController.onDefaultPlay( + context, widget.playOnMiniPlayer), + style: FilledButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.all(Radius.circular(8))), + backgroundColor: theme.primaryColorLight), + label: Text( + "Play", + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 16), + ), + icon: Icon(Icons.play_arrow), ), - icon: Icon(Icons.play_arrow), - ), - ) - ], + ) + ], + ), ), - ), - ListTile( - onTap: () => onTapEpisode(index, context, episodes), - trailing: StreamBuilder( - stream: GetAudioPlayer().audioHandler.mediaItem, - builder: (context, snapshot) { - MediaItem? mediaItem = snapshot.data; - return mediaItem != null && - mediaItem.id == item.enclosureUrl - ? SizedBox( - height: 30, - width: 30, - child: SpinKitWave( - itemCount: 4, - type: SpinKitWaveType.center, - size: 15, - color: theme.primaryColorLight, + ListTile( + onTap: () => playerController.onTapEpisode( + index, context, episodes, widget.playOnMiniPlayer), + trailing: StreamBuilder( + stream: GetAudioPlayer().audioHandler.mediaItem, + builder: (context, snapshot) { + MediaItem? mediaItem = snapshot.data; + return mediaItem != null && + mediaItem.id == item.enclosureUrl + ? SizedBox( + height: 30, + width: 30, + child: SpinKitWave( + itemCount: 4, + type: SpinKitWaveType.center, + size: 15, + color: theme.primaryColorLight, + ), + ) + : Icon(Icons.play_circle_outline_outlined); + }), + leading: CachedImage( + imageUrl: item.image, + imageHeight: 48, + imageWidth: 48, + loadingIndicatorSize: 25, + ), + title: Text( + item.title!, + maxLines: 2, + style: TextStyle(fontSize: 13, fontWeight: FontWeight.w500), + ), + subtitle: item.duration != null || item.episode != null + ? Row( + children: [ + if (item.episode != null) + Text( + "#${item.episode} ${item.duration != null ? " • " : ""} ", + style: TextStyle(fontSize: 11), ), - ) - : Icon(Icons.play_circle_outline_outlined); - }), - leading: CachedImage( - imageUrl: item.image, - imageHeight: 48, - imageWidth: 48, - loadingIndicatorSize: 25, - ), - title: Text( - item.title!, - maxLines: 2, - style: TextStyle(fontSize: 13, fontWeight: FontWeight.w500), + if (item.duration != null) + Text( + formatDuration(item.duration!), + style: TextStyle(fontSize: 11), + ), + ], + ) + : null, ), - subtitle: item.duration != null || item.episode != null - ? Row( - children: [ - if (item.episode != null) - Text( - "#${item.episode} ${item.duration != null ? " • " : ""} ", - style: TextStyle(fontSize: 11), - ), - if (item.duration != null) - Text( - formatDuration(item.duration!), - style: TextStyle(fontSize: 11), - ), - ], - ) - : null, - ), - ], + ], + ), ); }, ); } - void _initiatePlay( - BuildContext context, List episodes, int index) { - if (!GetAudioPlayer().audioHandler.isInitiated) { - GetAudioPlayer().audioHandler.isInitiated = true; - } - GetAudioPlayer().audioHandler.play(); - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => NewPodcastEpidosePlayer( - currentPodcastIndex: index, podcastEpisodes: episodes), - ), - ); - } - - void onTapEpisode( - int index, BuildContext context, List episodes) async { - await _addEpisodesToQueue(episodes); - GetAudioPlayer().audioHandler.skipToQueueItem(index); - _initiatePlay(context, episodes, index); - } - String formatDuration(int seconds) { Duration duration = Duration(seconds: seconds); @@ -248,17 +225,4 @@ class _PodcastEpisodesViewState extends State { return '${duration.inHours}:${(duration.inMinutes % 60).toString().padLeft(2, '0')}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}'; } } - - Future _addEpisodesToQueue(List items) async { - GetAudioPlayer audioPlayer = GetAudioPlayer(); - await audioPlayer.audioHandler.updateQueue([]); - print(audioPlayer.audioHandler.queue.value.length); - await audioPlayer.audioHandler.addQueueItems(items - .map((e) => MediaItem( - id: e.enclosureUrl ?? "", - title: e.title ?? "", - artUri: Uri.parse(e.image ?? ""), - duration: Duration(seconds: e.duration ?? 0))) - .toList()); - } } diff --git a/lib/src/screens/podcast/view/podcast_trending.dart b/lib/src/screens/podcast/view/podcast_trending.dart index 372d55bd..76a8749d 100644 --- a/lib/src/screens/podcast/view/podcast_trending.dart +++ b/lib/src/screens/podcast/view/podcast_trending.dart @@ -2,10 +2,12 @@ import 'package:acela/src/models/podcast/podcast_categories_response.dart'; import 'package:acela/src/models/podcast/trending_podcast_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/podcast/controller/podcast_controller.dart'; +import 'package:acela/src/screens/podcast/controller/podcast_player_controller.dart'; import 'package:acela/src/screens/podcast/view/add_rss_podcast.dart'; import 'package:acela/src/screens/podcast/view/liked_podcasts.dart'; import 'package:acela/src/screens/podcast/view/local_podcast_episode.dart'; import 'package:acela/src/screens/podcast/view/podcast_search.dart'; +import 'package:acela/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_categories_body.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_feed_item.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_feeds_body.dart'; @@ -13,11 +15,14 @@ import 'package:acela/src/screens/upload/podcast/podcast_upload_screen.dart'; import 'package:acela/src/utils/podcast/podcast_communicator.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:miniplayer/miniplayer.dart'; import 'package:provider/provider.dart'; import '../../../widgets/fab_custom.dart'; import '../../../widgets/fab_overlay.dart'; +final miniPlayerNavigatorkey = GlobalKey(); + class PodCastTrendingScreen extends StatefulWidget { const PodCastTrendingScreen({ Key? key, @@ -65,9 +70,12 @@ class _PodCastTrendingScreenState extends State Widget getList(List items) { return ListView.separated( itemBuilder: (c, i) { - return PodcastFeedItemWidget( - appData: widget.appData, - item: items[i], + return Padding( + padding: EdgeInsets.only(bottom: i == items.length - 1 ? 65.0 : 0), + child: PodcastFeedItemWidget( + appData: widget.appData, + item: items[i], + ), ); }, separatorBuilder: (c, i) => const Divider(height: 0), @@ -86,65 +94,113 @@ class _PodCastTrendingScreenState extends State : currentIndex == 3 ? 'Recent Podcasts & Episodes' : 'Live Podcasts'; - return DefaultTabController( - length: 5, - child: Scaffold( - appBar: AppBar( - leadingWidth: 30, - title: ListTile( - contentPadding: EdgeInsets.zero, - leading: Image.asset( - 'assets/pod-cast-logo-round.png', - width: 40, - height: 40, - ), - title: Text('Podcasts'), - subtitle: Text(text), - ), - bottom: TabBar( - controller: _tabController, - tabs: [ - Tab(icon: const Icon(Icons.trending_up)), - Tab(icon: const Icon(FontAwesomeIcons.rss)), - Tab(icon: const Icon(Icons.category)), - Tab(icon: const Icon(Icons.music_note)), - Tab(icon: const Icon(Icons.live_tv)), - ], - ), - actions: [ - IconButton( - onPressed: () { - var screen = PodCastSearch(appData: widget.appData); - var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); - }, - icon: Icon(Icons.search), - ), - _postPodcastButton(widget.appData) - ], - ), - body: SafeArea( - child: Stack( - children: [ - TabBarView( - controller: _tabController, - children: [ - PodcastFeedsBody( - future: trendingFeeds, appData: widget.appData), - _rssPodcastTab(context), - PodcastCategoriesBody( - appData: widget.appData, - future: categories, + return MiniplayerWillPopScope( + onWillPop: () async { + final NavigatorState navigatorState = + miniPlayerNavigatorkey.currentState!; + if (!navigatorState.canPop()) return true; + navigatorState.pop(); + return false; + }, + child: Stack( + children: [ + Navigator( + key: miniPlayerNavigatorkey, + onGenerateRoute: (settings) => MaterialPageRoute( + settings: settings, + builder: (context) => DefaultTabController( + length: 5, + child: Scaffold( + appBar: AppBar( + leadingWidth: 30, + title: ListTile( + contentPadding: EdgeInsets.zero, + leading: Image.asset( + 'assets/pod-cast-logo-round.png', + width: 40, + height: 40, + ), + title: Text('Podcasts'), + subtitle: Text(text), + ), + bottom: TabBar( + controller: _tabController, + tabs: [ + Tab(icon: const Icon(Icons.trending_up)), + Tab(icon: const Icon(FontAwesomeIcons.rss)), + Tab(icon: const Icon(Icons.category)), + Tab(icon: const Icon(Icons.music_note)), + Tab(icon: const Icon(Icons.live_tv)), + ], + ), + actions: [ + IconButton( + onPressed: () { + var screen = PodCastSearch(appData: widget.appData); + var route = MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); + }, + icon: Icon(Icons.search), + ), + _postPodcastButton(widget.appData) + ], + ), + body: SafeArea( + child: Stack( + children: [ + TabBarView( + controller: _tabController, + children: [ + PodcastFeedsBody( + future: trendingFeeds, appData: widget.appData), + _rssPodcastTab(context), + PodcastCategoriesBody( + appData: widget.appData, + future: categories, + ), + PodcastFeedsBody( + future: recentFeeds, appData: widget.appData), + PodcastFeedsBody( + future: liveFeeds, appData: widget.appData), + ], + ), + Consumer( + builder: (context, value, child) { + return Padding( + padding: EdgeInsets.only( + bottom: value.episodes.isEmpty ? 0 : 65.0), + child: _fabContainer(), + ); + }, + ) + ], + ), ), - PodcastFeedsBody( - future: recentFeeds, appData: widget.appData), - PodcastFeedsBody(future: liveFeeds, appData: widget.appData), - ], + ), ), - _fabContainer() - ], + ), ), - ), + Consumer( + builder: (context, value, child) { + return Miniplayer( + controller: value.miniplayerController, + minHeight: value.episodes.isEmpty ? 0 : 65, + maxHeight: MediaQuery.of(context).size.height, + builder: (height, percentage) { + if (value.episodes.isEmpty) { + return SizedBox.shrink(); + } else { + return NewPodcastEpidosePlayer( + key: ValueKey(value.episodes.first.id), + dragValue: percentage, + podcastEpisodes: value.episodes, + currentPodcastIndex: value.index); + } + }, + ); + }, + ) + ], ), ); } @@ -233,7 +289,8 @@ class _PodCastTrendingScreenState extends State isMenuOpen = false; var screen = PodCastSearch(appData: widget.appData); var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); + Navigator.of(miniPlayerNavigatorkey.currentState!.context) + .push(route); }); }, ); @@ -245,7 +302,8 @@ class _PodCastTrendingScreenState extends State isMenuOpen = false; var screen = LikedPodcasts(appData: widget.appData); var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); + Navigator.of(miniPlayerNavigatorkey.currentState!.context) + .push(route); }); }, ); @@ -259,7 +317,8 @@ class _PodCastTrendingScreenState extends State appData: widget.appData, ); var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); + Navigator.of(miniPlayerNavigatorkey.currentState!.context) + .push(route); }); }, ); diff --git a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart index 28f52061..d232ff73 100644 --- a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart +++ b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart @@ -13,6 +13,7 @@ import 'package:acela/src/screens/podcast/widgets/podcast_info_description.dart' import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/download_podcast_button.dart'; import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart'; +import 'package:acela/src/screens/podcast/widgets/podcast_player_widgets/progress_bar.dart'; import 'package:acela/src/utils/seconds_to_duration.dart'; import 'package:acela/src/widgets/cached_image.dart'; import 'package:audio_service/audio_service.dart'; @@ -28,11 +29,13 @@ class NewPodcastEpidosePlayer extends StatefulWidget { const NewPodcastEpidosePlayer( {Key? key, required this.podcastEpisodes, + required this.dragValue, required this.currentPodcastIndex}) : super(key: key); final List podcastEpisodes; final int currentPodcastIndex; + final double dragValue; @override State createState() => @@ -151,136 +154,228 @@ class _NewPodcastEpidosePlayerState extends State { return ChangeNotifierProvider.value( value: chapterController, child: Scaffold( - body: SafeArea( - child: Stack( - fit: StackFit.expand, - children: [ - if (originalImage != null && originalImage!.isNotEmpty) - CachedImage( - imageUrl: originalImage, - ), - if (originalImage != null && originalImage!.isNotEmpty) - Positioned.fill( - child: ClipRRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 40, sigmaY: 40), - child: const SizedBox.shrink(), - ), + body: Stack( + fit: StackFit.expand, + children: [ + if (originalImage != null && originalImage!.isNotEmpty) + CachedImage( + imageUrl: originalImage, + ), + if (originalImage != null && originalImage!.isNotEmpty) + Positioned.fill( + child: ClipRRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 40, sigmaY: 40), + child: const SizedBox.shrink(), ), ), - Positioned.fill( - child: Container( - decoration: BoxDecoration( - gradient: LinearGradient(colors: [ - theme.primaryColorDark, - theme.primaryColorDark.withOpacity(0.3) - ])), - )), - StreamBuilder( - stream: _audioHandler.mediaItem, - builder: (context, snapshot) { - return Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Spacer(), - _audioHandler.shouldPlayVideo() - ? SizedBox( - height: MediaQuery.of(context).size.height * 0.45, - child: Center( - child: ValueListenableBuilder( - valueListenable: - _audioHandler.aspectRatioNotifier, - builder: (context, aspectRatio, child) { - return AspectRatio( - aspectRatio: aspectRatio ?? 1.5, - child: child); - }, - child: VideoPlayer( - _audioHandler.videoPlayerController!), - )), - ) - : Container( - margin: EdgeInsets.symmetric(horizontal: 30), - constraints: BoxConstraints( - maxHeight: - MediaQuery.of(context).size.height * - 0.45), - child: - Selector( - selector: (_, myType) => myType.image, - builder: (context, chapterImage, child) { - return CachedImage( - imageUrl: chapterImage ?? originalImage, - imageHeight: - MediaQuery.of(context).size.height * - 0.45, - ); - }, - )), - Spacer(), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10), - child: Column( - children: [ - _title(screenWidth), - const SizedBox( - height: 5, - ), - Text( - currentPodcastEpisode.datePublishedPretty - .toString(), - style: TextStyle(fontSize: 12), - ), - ], + ), + Positioned.fill( + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + theme.primaryColorDark, + theme.primaryColorDark.withOpacity(0.3) + ])), + )), + // if (widget.dragValue < 0.5) + Positioned( + top: 0, + left: 0, + right: 0, + child: Visibility( + maintainAnimation: true, + maintainSize: true, + maintainState: true, + visible: widget.dragValue < 0.5, + child: PodcastProgressBar( + duration: currentPodcastEpisode.duration, + positionStream: _positionDataStream), + )), + StreamBuilder( + stream: _audioHandler.mediaItem, + builder: (context, snapshot) { + return SingleChildScrollView( + physics: NeverScrollableScrollPhysics(), + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Spacer(), + _audioHandler.shouldPlayVideo() + ? SizedBox( + height: + MediaQuery.of(context).size.height * 0.45, + child: Center( + child: ValueListenableBuilder( + valueListenable: + _audioHandler.aspectRatioNotifier, + builder: (context, aspectRatio, child) { + return AspectRatio( + aspectRatio: aspectRatio ?? 1.5, + child: child); + }, + child: VideoPlayer( + _audioHandler.videoPlayerController!), + )), + ) + : Transform.translate( + offset: Offset( + lerpDouble(-150, 0, widget.dragValue) ?? 0, + lerpDouble(-152.5, 0, widget.dragValue) ?? 0, + ), + child: Container( + height: lerpDouble( + 50, + MediaQuery.of(context).size.height * + 0.45, + widget.dragValue) ?? + 0, + width: lerpDouble( + 50, + MediaQuery.of(context).size.width * + 0.85, + widget.dragValue) ?? + 0, + margin: + EdgeInsets.symmetric(horizontal: 30), + // constraints: BoxConstraints( + // maxHeight: MediaQuery.of(context) + // .size + // .height * + // 0.45), + child: Selector( + selector: (_, myType) => myType.image, + builder: (context, chapterImage, child) { + return CachedImage( + imageUrl: + chapterImage ?? originalImage, + imageHeight: MediaQuery.of(context) + .size + .height * + 0.45, + ); + }, + )), + ), + Spacer(), + AnimatedOpacity( + opacity: widget.dragValue == 1 + ? 1 + : widget.dragValue.clamp(0, 0.5), + duration: Duration(milliseconds: 150), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + vertical: 15.0, horizontal: 10), + child: Column( + children: [ + _title(screenWidth * 0.85), + const SizedBox( + height: 5, + ), + Text( + currentPodcastEpisode.datePublishedPretty + .toString(), + style: TextStyle(fontSize: 12), + ), + ], + ), + ), + userToolbar(theme), + _slider(), + Gap(10), + ControlButtons( + _audioHandler, + chapterController: chapterController, + podcastEpisode: currentPodcastEpisode, + showSkipPreviousButtom: + widget.podcastEpisodes.length > 1, + positionStream: + _positionDataStream.asBroadcastStream(), + ), + ], + ), ), - ), - userToolbar(theme), - PodcastPlayerSlider( - episode: currentPodcastEpisode, + Spacer(), + ], + ), + ), + ); + }, + ), + if (widget.dragValue < 0.5) + AnimatedPositioned( + top: lerpDouble(10, 0, widget.dragValue), + left: lerpDouble(80, 20, widget.dragValue), + right: 10, + duration: Duration(milliseconds: 100), + child: AnimatedOpacity( + opacity: (lerpDouble(1, 6, widget.dragValue * (-0.5)) ?? 0) + .clamp(0, 1), + duration: Duration(milliseconds: 100), + child: Padding( + padding: const EdgeInsets.only(left: 0.0, right: 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Align( + alignment: Alignment.centerLeft, + child: _title(screenWidth * 0.75, + height: 15, fontSize: 14)), + ControlButtons( + _audioHandler, + smallSize: true, chapterController: chapterController, - audioPlayerHandler: _audioHandler, - positionDataStream: _positionDataStream, - currentPodcastEpisodeDuration: - currentPodcastEpisode.duration), - Gap(10), - ControlButtons( - _audioHandler, - chapterController: chapterController, - podcastEpisode: currentPodcastEpisode, - showSkipPreviousButtom: - widget.podcastEpisodes.length > 1, - positionStream: _positionDataStream.asBroadcastStream(), - ), - Spacer(), - ], - ); - }, + podcastEpisode: currentPodcastEpisode, + showSkipPreviousButtom: + widget.podcastEpisodes.length > 1, + positionStream: + _positionDataStream.asBroadcastStream(), + ), + ], + ), + ), + ), ), - ], - ), + ], ), ), ); } - Selector _title(double screenWidth) { + PodcastPlayerSlider _slider() { + return PodcastPlayerSlider( + episode: currentPodcastEpisode, + chapterController: chapterController, + audioPlayerHandler: _audioHandler, + positionDataStream: _positionDataStream, + currentPodcastEpisodeDuration: currentPodcastEpisode.duration); + } + + Selector _title(double maxwidth, + {double fontSize = 20, double height = 25}) { return Selector( selector: (_, myType) => myType.title, builder: (context, chapterTitle, child) { return SizedBox( - width: screenWidth * 0.85, - height: 25, + width: maxwidth, + height: height, child: Utilities.textLines( chapterTitle ?? originalTitle, - TextStyle(fontWeight: FontWeight.bold, fontSize: 20), - screenWidth * 0.85, + TextStyle( + fontWeight: FontWeight.bold, fontSize: fontSize), + maxwidth, 3) > 1 ? Marquee( text: chapterTitle ?? originalTitle, - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: fontSize), scrollAxis: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.start, blankSpace: 50, @@ -300,7 +395,8 @@ class _NewPodcastEpidosePlayerState extends State { textAlign: TextAlign.center, maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: fontSize), ), ); }, diff --git a/lib/src/screens/podcast/widgets/podcast_feed_item.dart b/lib/src/screens/podcast/widgets/podcast_feed_item.dart index 77288a2a..59224833 100644 --- a/lib/src/screens/podcast/widgets/podcast_feed_item.dart +++ b/lib/src/screens/podcast/widgets/podcast_feed_item.dart @@ -12,12 +12,14 @@ class PodcastFeedItemWidget extends StatefulWidget { {Key? key, required this.item, required this.appData, - this.showLikeButton = true}) + this.showLikeButton = true, + this.playOnMiniPlayer = true}) : super(key: key); final PodCastFeedItem item; final HiveUserData appData; final bool showLikeButton; + final bool playOnMiniPlayer; @override State createState() => _PodcastFeedItemWidgetState(); @@ -54,9 +56,10 @@ class _PodcastFeedItemWidgetState extends State { }), ), onTap: () { - // var screen = - // PodcastFeedScreen(appData: widget.appData, item: widget.item); - var screen = PodcastEpisodesView(feedItem: widget.item); + var screen = PodcastEpisodesView( + feedItem: widget.item, + playOnMiniPlayer: widget.playOnMiniPlayer, + ); var route = MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); }, diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart index 72b8320b..9d41fd07 100644 --- a/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/control_buttons.dart @@ -16,13 +16,15 @@ class ControlButtons extends StatelessWidget { required this.showSkipPreviousButtom, required this.podcastEpisode, required this.positionStream, - required this.chapterController}) + required this.chapterController, + this.smallSize = false}) : super(key: key); final bool showSkipPreviousButtom; final PodcastEpisode podcastEpisode; final Stream positionStream; final PodcastChapterController chapterController; + final bool smallSize; @override Widget build(BuildContext context) { @@ -30,6 +32,8 @@ class ControlButtons extends StatelessWidget { bool isPaused = false; Color iconColor = theme.primaryColorLight; return Row( + mainAxisAlignment: + smallSize ? MainAxisAlignment.center : MainAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Visibility( @@ -55,19 +59,20 @@ class ControlButtons extends StatelessWidget { }, ), ), - StreamBuilder( - stream: positionStream, - builder: (context, snapshot) { - final positionData = snapshot.data ?? - PositionData(Duration.zero, Duration.zero, Duration.zero); - return PodcastPlayerInteractionIconButton( - size: 35, - horizontalPadding: 20, - onPressed: () => goBackTenSeconds(positionData), - icon: Icons.replay_10, - color: iconColor); - }, - ), + if (!smallSize) + StreamBuilder( + stream: positionStream, + builder: (context, snapshot) { + final positionData = snapshot.data ?? + PositionData(Duration.zero, Duration.zero, Duration.zero); + return PodcastPlayerInteractionIconButton( + size: 35, + horizontalPadding: 20, + onPressed: () => goBackTenSeconds(positionData), + icon: Icons.replay_10, + color: iconColor); + }, + ), StreamBuilder( stream: audioHandler.playbackState, builder: (context, snapshot) { @@ -78,26 +83,43 @@ class ControlButtons extends StatelessWidget { audioHandler.play(); if (processingState == AudioProcessingState.loading || processingState == AudioProcessingState.buffering) { - return CircleAvatar( - radius: 32, - backgroundColor: theme.primaryColorLight, - child: CircularProgressIndicator( - strokeWidth: 2.5, - color: theme.primaryColorDark, - ), - ); + return smallSize + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 2), + child: SizedBox( + height: 15, + width: 15, + child: CircularProgressIndicator( + strokeWidth: 1, + color: theme.primaryColorLight, + ), + ), + ) + : CircleAvatar( + radius: smallSize ? 20 : 32, + backgroundColor: theme.primaryColorLight, + child: CircularProgressIndicator( + strokeWidth: 2.5, + color: theme.primaryColorDark, + ), + ); } else if (playing != true) { return GestureDetector( onTap: audioHandler.play, - child: CircleAvatar( - radius: 32, - backgroundColor: theme.primaryColorLight, - child: Icon( - Icons.play_arrow, - size: 35, - color: Colors.black, - ), - ), + child: smallSize + ? Icon( + Icons.play_arrow, + size: 20, + ) + : CircleAvatar( + radius: 32, + backgroundColor: theme.primaryColorLight, + child: Icon( + Icons.play_arrow, + size: 35, + color: Colors.black, + ), + ), ); } else { _continueFromDuration(context); @@ -106,32 +128,38 @@ class ControlButtons extends StatelessWidget { isPaused = !isPaused; audioHandler.pause(); }, - child: CircleAvatar( - radius: 32, - backgroundColor: theme.primaryColorLight, - child: Icon( - Icons.pause, - size: 35, - color: Colors.black, - ), - ), + child: smallSize + ? Icon( + Icons.pause, + size: 20, + ) + : CircleAvatar( + radius: 32, + backgroundColor: theme.primaryColorLight, + child: Icon( + Icons.pause, + size: 35, + color: theme.primaryColorDark, + ), + ), ); } }, ), - StreamBuilder( - stream: positionStream, - builder: (context, snapshot) { - final positionData = snapshot.data ?? - PositionData(Duration.zero, Duration.zero, Duration.zero); - return PodcastPlayerInteractionIconButton( - size: 35, - horizontalPadding: 20, - onPressed: () => _goForwardTenSeconds(positionData), - icon: Icons.forward_10, - color: iconColor); - }, - ), + if (!smallSize) + StreamBuilder( + stream: positionStream, + builder: (context, snapshot) { + final positionData = snapshot.data ?? + PositionData(Duration.zero, Duration.zero, Duration.zero); + return PodcastPlayerInteractionIconButton( + size: 35, + horizontalPadding: 20, + onPressed: () => _goForwardTenSeconds(positionData), + icon: Icons.forward_10, + color: iconColor); + }, + ), Visibility( visible: showSkipPreviousButtom, child: StreamBuilder( diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart index da61c3a9..be7118b0 100644 --- a/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/podcast_player_slider.dart @@ -80,7 +80,7 @@ class PodcastPlayerSlider extends StatelessWidget { ); } - String formatDuration(int seconds) { + static String formatDuration(int seconds) { Duration duration = Duration(seconds: seconds); if (duration.inHours < 1) { diff --git a/lib/src/screens/podcast/widgets/podcast_player_widgets/progress_bar.dart b/lib/src/screens/podcast/widgets/podcast_player_widgets/progress_bar.dart new file mode 100644 index 00000000..8645695f --- /dev/null +++ b/lib/src/screens/podcast/widgets/podcast_player_widgets/progress_bar.dart @@ -0,0 +1,51 @@ +import 'package:acela/src/screens/podcast/widgets/audio_player/action_tools.dart'; +import 'package:flutter/material.dart'; + +class PodcastProgressBar extends StatefulWidget { + const PodcastProgressBar( + {required this.duration, required this.positionStream}); + + final int? duration; + final Stream positionStream; + + @override + State createState() => _PodcastProgressBarState(); +} + +class _PodcastProgressBarState extends State + with AutomaticKeepAliveClientMixin { + double initialValue = 0; + + @override + Widget build(BuildContext context) { + super.build(context); + final theme = Theme.of(context); + return StreamBuilder( + stream: widget.positionStream, + builder: (context, snapshot) { + final positionData = snapshot.data ?? + PositionData(Duration.zero, Duration.zero, Duration.zero); + return SizedBox( + height: 1.5, + child: LinearProgressIndicator( + color: theme.primaryColorLight, value: value(positionData)), + ); + }, + ); + } + + double value(PositionData positionData) { + double position = (positionData.position.inMilliseconds / + positionData.duration.inMilliseconds); + initialValue = position.isNaN ? initialValue : position; + return position.isNaN + ? initialValue + : (positionData.position.inMilliseconds / + positionData.duration.inMilliseconds) + .clamp(0.0, 1.0) + .toDouble(); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/pubspec.lock b/pubspec.lock index e35af9f2..87ec36e7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1082,6 +1082,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + miniplayer: + dependency: "direct main" + description: + name: miniplayer + sha256: "6e12c27aef7432fc16508460a6dc824f3edfeb01761bd0dbfbccc84d516121bf" + url: "https://pub.dev" + source: hosted + version: "1.0.1" nested: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5b6c8b47..5262d7be 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -99,6 +99,7 @@ dependencies: gap: ^3.0.1 marquee: ^2.2.3 flutter_spinkit: ^5.2.1 + miniplayer: ^1.0.1 dev_dependencies: flutter_test: From 8168439cc6f67a4ca547f5fefa5312d2d67a842a Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 2 May 2024 16:23:04 +0530 Subject: [PATCH 404/466] mandatory posting authoriy requirement for logging in --- android/app/src/main/assets/index.html | 11 + .../kotlin/tv/threespeak/app/MainActivity.kt | 11 +- .../models/user_account/action_response.dart | 41 ++ lib/src/models/user_account/active_model.dart | 34 + .../user_account/delayed_vote_model.dart | 28 + .../user_account/downvote_manarbar_model.dart | 28 + .../user_account/posting_json_meta_data.dart | 117 ++++ lib/src/models/user_account/user_model.dart | 596 ++++++++++++++++++ .../user_account/voting_manabar_model.dart | 28 + .../home_screen/home_screen_feed_list.dart | 81 +-- lib/src/screens/login/ha_login_screen.dart | 164 +++-- lib/src/utils/communicator.dart | 20 + lib/src/widgets/retry.dart | 2 + pubspec.lock | 24 +- 14 files changed, 1072 insertions(+), 113 deletions(-) create mode 100644 lib/src/models/user_account/action_response.dart create mode 100644 lib/src/models/user_account/active_model.dart create mode 100644 lib/src/models/user_account/delayed_vote_model.dart create mode 100644 lib/src/models/user_account/downvote_manarbar_model.dart create mode 100644 lib/src/models/user_account/posting_json_meta_data.dart create mode 100644 lib/src/models/user_account/user_model.dart create mode 100644 lib/src/models/user_account/voting_manabar_model.dart diff --git a/android/app/src/main/assets/index.html b/android/app/src/main/assets/index.html index 09c02393..c75d1461 100644 --- a/android/app/src/main/assets/index.html +++ b/android/app/src/main/assets/index.html @@ -904,6 +904,17 @@ }); } + async function getAccountInfo(accountName) { + const response = await dhiveClient.database.call("get_accounts", [[accountName]]); + replyToNative({ + id: 'identifier', + type: "getAccountInfo", + data: response[0], + valid: true, + error: "", + }); + } + function replyToNative(result) { // window.webkit.messageHandlers.acela.postMessage(result); Android.postMessage(JSON.stringify(result)); diff --git a/android/app/src/main/kotlin/tv/threespeak/app/MainActivity.kt b/android/app/src/main/kotlin/tv/threespeak/app/MainActivity.kt index d9f06109..ce41f81e 100644 --- a/android/app/src/main/kotlin/tv/threespeak/app/MainActivity.kt +++ b/android/app/src/main/kotlin/tv/threespeak/app/MainActivity.kt @@ -146,7 +146,12 @@ class MainActivity : AudioServiceActivity() { && hasAuthkey != null ) { webView?.evaluateJavascript("commentOnContent('$user', '$author', '$permlink', '$comment', '$postingKey', '$hasKey', '$hasAuthkey');", null) - } + } else if (call.method == "getAccountInfo" && username != null ) { + webView?.evaluateJavascript( + "getAccountInfo('$username');", + null + ) + } } } @@ -232,6 +237,9 @@ class WebAppInterface(private val mContext: Context) { JSBridgeAction.DO_WE_HAVE_POSTING_AUTH.value -> { main.result?.success(message) } + JSBridgeAction.GET_ACCOUNT_INFO.value -> { + main.result?.success(message) + } } } } @@ -254,4 +262,5 @@ enum class JSBridgeAction(val value: String) { GET_ENCRYPTED_CHALLENGE("getEncryptedChallenge"), GET_DECRYPTED_CHALLENGE("getDecryptedChallenge"), DO_WE_HAVE_POSTING_AUTH("doWeHavePostingAuth"), + GET_ACCOUNT_INFO("getAccountInfo"), } diff --git a/lib/src/models/user_account/action_response.dart b/lib/src/models/user_account/action_response.dart new file mode 100644 index 00000000..817318eb --- /dev/null +++ b/lib/src/models/user_account/action_response.dart @@ -0,0 +1,41 @@ +import 'dart:convert'; + +enum ResponseStatus { success, failed, unknown } + +class ActionSingleDataResponse { + final String? id; + final String? type; + final T? data; + final bool valid; + final String errorMessage; + final ResponseStatus status; + final bool isSuccess; + + ActionSingleDataResponse( + {this.id, + this.type, + this.data, + this.isSuccess = false, + this.valid = false, + required this.errorMessage, + required this.status}); + + factory ActionSingleDataResponse.fromJsonString( + String string, T Function(Map) fromJson) => + ActionSingleDataResponse.fromJson(json.decode(string), fromJson); + + factory ActionSingleDataResponse.fromJson( + Map json, T Function(Map) fromJson) { + return ActionSingleDataResponse( + id: json['id'] as String, + type: json['type'] as String, + data: fromJson(json['data']), + valid: json['valid'] as bool, + status: json['valid'] && json['error'].isEmpty + ? ResponseStatus.success + : ResponseStatus.failed, + isSuccess: json['valid'] && json['error'].isEmpty, + errorMessage: json['error'] as String, + ); + } +} diff --git a/lib/src/models/user_account/active_model.dart b/lib/src/models/user_account/active_model.dart new file mode 100644 index 00000000..4fbe7c38 --- /dev/null +++ b/lib/src/models/user_account/active_model.dart @@ -0,0 +1,34 @@ +class ActiveModel { + final List>? accountAuths; + final List>? keyAuths; + final int? weightThreshold; + + ActiveModel({ + this.accountAuths, + this.keyAuths, + this.weightThreshold, + }); + + ActiveModel copyWith({ + List>? accountAuths, + List>? keyAuths, + int? weightThreshold, + }) => + ActiveModel( + accountAuths: accountAuths ?? this.accountAuths, + keyAuths: keyAuths ?? this.keyAuths, + weightThreshold: weightThreshold ?? this.weightThreshold, + ); + + factory ActiveModel.fromJson(Map json) => ActiveModel( + accountAuths: json["account_auths"] == null ? [] : List>.from(json["account_auths"]!.map((x) => List.from(x.map((x) => x)))), + keyAuths: json["key_auths"] == null ? [] : List>.from(json["key_auths"]!.map((x) => List.from(x.map((x) => x)))), + weightThreshold: json["weight_threshold"], + ); + + Map toJson() => { + "account_auths": accountAuths == null ? [] : List.from(accountAuths!.map((x) => List.from(x.map((x) => x)))), + "key_auths": keyAuths == null ? [] : List.from(keyAuths!.map((x) => List.from(x.map((x) => x)))), + "weight_threshold": weightThreshold, + }; +} diff --git a/lib/src/models/user_account/delayed_vote_model.dart b/lib/src/models/user_account/delayed_vote_model.dart new file mode 100644 index 00000000..2b74f559 --- /dev/null +++ b/lib/src/models/user_account/delayed_vote_model.dart @@ -0,0 +1,28 @@ +class DelayedVoteModel { + final DateTime? time; + final int? val; + + DelayedVoteModel({ + this.time, + this.val, + }); + + DelayedVoteModel copyWith({ + DateTime? time, + int? val, + }) => + DelayedVoteModel( + time: time ?? this.time, + val: val ?? this.val, + ); + + factory DelayedVoteModel.fromJson(Map json) => DelayedVoteModel( + time: json["time"] == null ? null : DateTime.parse(json["time"]), + val: json["val"], + ); + + Map toJson() => { + "time": time?.toIso8601String(), + "val": val, + }; +} diff --git a/lib/src/models/user_account/downvote_manarbar_model.dart b/lib/src/models/user_account/downvote_manarbar_model.dart new file mode 100644 index 00000000..4edbd000 --- /dev/null +++ b/lib/src/models/user_account/downvote_manarbar_model.dart @@ -0,0 +1,28 @@ +class DownvoteManabarModel { + final int? currentMana; + final int? lastUpdateTime; + + DownvoteManabarModel({ + this.currentMana, + this.lastUpdateTime, + }); + + DownvoteManabarModel copyWith({ + int? currentMana, + int? lastUpdateTime, + }) => + DownvoteManabarModel( + currentMana: currentMana ?? this.currentMana, + lastUpdateTime: lastUpdateTime ?? this.lastUpdateTime, + ); + + factory DownvoteManabarModel.fromJson(Map json) => DownvoteManabarModel( + currentMana: json["current_mana"], + lastUpdateTime: json["last_update_time"], + ); + + Map toJson() => { + "current_mana": currentMana, + "last_update_time": lastUpdateTime, + }; +} diff --git a/lib/src/models/user_account/posting_json_meta_data.dart b/lib/src/models/user_account/posting_json_meta_data.dart new file mode 100644 index 00000000..9be207cf --- /dev/null +++ b/lib/src/models/user_account/posting_json_meta_data.dart @@ -0,0 +1,117 @@ +import 'dart:convert'; + +import 'package:acela/src/utils/safe_convert.dart'; + +class UserPostingJsonMetadata { + final UserPostingJsonMetadataProfile? profile; + + UserPostingJsonMetadata({ + this.profile, + }); + + UserPostingJsonMetadata copyWith({ + UserPostingJsonMetadataProfile? profile, + }) => + UserPostingJsonMetadata( + profile: profile ?? this.profile, + ); + + factory UserPostingJsonMetadata.fromJson(Map json) => + UserPostingJsonMetadata( + profile: json["profile"] == null + ? null + : UserPostingJsonMetadataProfile.fromJson(json["profile"]), + ); + + factory UserPostingJsonMetadata.fromRawJson(String str) => + UserPostingJsonMetadata.fromJson(json.decode(str)); + + Map toJson() => { + "profile": profile?.toJson(), + }; +} + +class UserPostingJsonMetadataProfile { + final String? name; + final String? about; + final String? coverImage; + final String? profileImage; + final String? website; + final String? location; + final String? pinned; + final int? version; + final bool? trail; + final String? witnessDescription; + final List? tokens; + + UserPostingJsonMetadataProfile({ + this.name, + this.about, + this.coverImage, + this.profileImage, + this.website, + this.location, + this.pinned, + this.version, + this.trail, + this.witnessDescription, + this.tokens, + }); + + UserPostingJsonMetadataProfile copyWith({ + String? name, + String? about, + String? coverImage, + String? profileImage, + String? website, + String? location, + String? pinned, + int? version, + bool? trail, + String? witnessDescription, + List? tokens, + }) => + UserPostingJsonMetadataProfile( + name: name ?? this.name, + about: about ?? this.about, + coverImage: coverImage ?? this.coverImage, + profileImage: profileImage ?? this.profileImage, + website: website ?? this.website, + location: location ?? this.location, + pinned: pinned ?? this.pinned, + version: version ?? this.version, + trail: trail ?? this.trail, + witnessDescription: witnessDescription ?? this.witnessDescription, + tokens: tokens ?? this.tokens, + ); + + factory UserPostingJsonMetadataProfile.fromJson(Map json) => + UserPostingJsonMetadataProfile( + name: json["name"], + about: json["about"], + coverImage: json["cover_image"], + profileImage: json["profile_image"], + website: json["website"], + location: json["location"], + pinned: json["pinned"], + version: json["version"], + trail: json["trail"], + witnessDescription: json["witness_description"], + tokens: asList(json, "tokens") + ); + + Map toJson() => { + "name": name, + "about": about, + "cover_image": coverImage, + "profile_image": profileImage, + "website": website, + "location": location, + "pinned": pinned, + "version": version, + "trail": trail, + "witness_description": witnessDescription, + "tokens": + tokens == null ? [] : List.from(tokens!.map((x) => x)), + }; +} diff --git a/lib/src/models/user_account/user_model.dart b/lib/src/models/user_account/user_model.dart new file mode 100644 index 00000000..04c73346 --- /dev/null +++ b/lib/src/models/user_account/user_model.dart @@ -0,0 +1,596 @@ +import 'dart:convert'; + +import 'package:acela/src/models/user_account/active_model.dart'; +import 'package:acela/src/models/user_account/delayed_vote_model.dart'; +import 'package:acela/src/models/user_account/downvote_manarbar_model.dart'; +import 'package:acela/src/models/user_account/posting_json_meta_data.dart'; +import 'package:acela/src/models/user_account/voting_manabar_model.dart'; +import 'package:acela/src/utils/safe_convert.dart'; + +List userModelFromJson(String str) => + List.from(json.decode(str).map((x) => UserModel.fromJson(x))); + +String userModelToJson(List data) => + json.encode(List.from(data.map((x) => x.toJson()))); + +class UserModel { + final ActiveModel? active; + final String balance; + final bool? canVote; + final int? commentCount; + final DateTime created; + final int? curationRewards; + final List? delayedVotes; + final String? delegatedVestingShares; + final DownvoteManabarModel? downvoteManabar; + final DateTime? governanceVoteExpirationTs; + final List? guestBloggers; + final String hbdBalance; + final DateTime? hbdLastInterestPayment; + final String? hbdSeconds; + final DateTime? hbdSecondsLastUpdate; + final int id; + final String? jsonMetadata; + final DateTime? lastAccountRecovery; + final DateTime? lastAccountUpdate; + final DateTime? lastOwnerUpdate; + final DateTime? lastPost; + final DateTime? lastRootPost; + final DateTime? lastVoteTime; + final int? lifetimeVoteCount; + final List? marketHistory; + final String? memoKey; + final bool? mined; + final String name; + final DateTime? nextVestingWithdrawal; + final int? openRecurrentTransfers; + final List? otherHistory; + final ActiveModel? owner; + final int? pendingClaimedAccounts; + final int? pendingTransfers; + final int? postBandwidth; + final int? postCount; + final List? postHistory; + final String? postVotingPower; + final ActiveModel? posting; + final UserPostingJsonMetadata? postingJsonMetadata; + final int? postingRewards; + final DateTime? previousOwnerUpdate; + final List? proxiedVsfVotes; + final String? proxy; + final String? receivedVestingShares; + final String? recoveryAccount; + final int? reputation; + final String? resetAccount; + final String? rewardHbdBalance; + final String? rewardHiveBalance; + final String? rewardVestingBalance; + final String? rewardVestingHive; + final String? savingsBalance; + final String? savingsHbdBalance; + final DateTime? savingsHbdLastInterestPayment; + final String? savingsHbdSeconds; + final DateTime? savingsHbdSecondsLastUpdate; + final int? savingsWithdrawRequests; + final List? tagsUsage; + final int? toWithdraw; + final List? transferHistory; + final String? vestingBalance; + final String? vestingShares; + final String? vestingWithdrawRate; + final List? voteHistory; + final VotingManabarModel? votingManabar; + final int? votingPower; + final int? withdrawRoutes; + final int? withdrawn; + final List? witnessVotes; + final int? witnessesVotedFor; + + UserModel({ + this.active, + required this.balance, + this.canVote, + this.commentCount, + required this.created, + this.curationRewards, + this.delayedVotes, + this.delegatedVestingShares, + this.downvoteManabar, + this.governanceVoteExpirationTs, + this.guestBloggers, + required this.hbdBalance, + this.hbdLastInterestPayment, + this.hbdSeconds, + this.hbdSecondsLastUpdate, + required this.id, + this.jsonMetadata, + this.lastAccountRecovery, + this.lastAccountUpdate, + this.lastOwnerUpdate, + this.lastPost, + this.lastRootPost, + this.lastVoteTime, + this.lifetimeVoteCount, + this.marketHistory, + this.memoKey, + this.mined, + required this.name, + this.nextVestingWithdrawal, + this.openRecurrentTransfers, + this.otherHistory, + this.owner, + this.pendingClaimedAccounts, + this.pendingTransfers, + this.postBandwidth, + this.postCount, + this.postHistory, + this.postVotingPower, + this.posting, + this.postingJsonMetadata, + this.postingRewards, + this.previousOwnerUpdate, + this.proxiedVsfVotes, + this.proxy, + this.receivedVestingShares, + this.recoveryAccount, + this.reputation, + this.resetAccount, + this.rewardHbdBalance, + this.rewardHiveBalance, + this.rewardVestingBalance, + this.rewardVestingHive, + this.savingsBalance, + this.savingsHbdBalance, + this.savingsHbdLastInterestPayment, + this.savingsHbdSeconds, + this.savingsHbdSecondsLastUpdate, + this.savingsWithdrawRequests, + this.tagsUsage, + this.toWithdraw, + this.transferHistory, + this.vestingBalance, + this.vestingShares, + this.vestingWithdrawRate, + this.voteHistory, + this.votingManabar, + this.votingPower, + this.withdrawRoutes, + this.withdrawn, + this.witnessVotes, + this.witnessesVotedFor, + }); + + bool hasThreeSpeakPostingAuthority() { + if (posting != null && + posting!.accountAuths != null && + posting!.accountAuths!.isNotEmpty) { + for (List? item in posting!.accountAuths!) { + if (item != null && item.isNotEmpty && item.first == "threespeak") { + return true; + } + } + } + return false; + } + + double _vestingToDouble(String? arg) { + double? value = 0; + String result = arg ?? ""; + if (result.isNotEmpty) { + int index = result.indexOf(" "); + value = double.tryParse(result.substring(0, index)); + } + return value ?? 0; + } + + double get delegatedVestingSharesValue => + _vestingToDouble(delegatedVestingShares); + + double get receivedVestingSharesValue => + _vestingToDouble(receivedVestingShares); + + double get vestingSharesValue => _vestingToDouble(vestingShares); + + UserModel copyWith({ + ActiveModel? active, + String? balance, + bool? canVote, + int? commentCount, + DateTime? created, + int? curationRewards, + List? delayedVotes, + String? delegatedVestingShares, + DownvoteManabarModel? downvoteManabar, + DateTime? governanceVoteExpirationTs, + List? guestBloggers, + String? hbdBalance, + DateTime? hbdLastInterestPayment, + String? hbdSeconds, + DateTime? hbdSecondsLastUpdate, + int? id, + String? jsonMetadata, + DateTime? lastAccountRecovery, + DateTime? lastAccountUpdate, + DateTime? lastOwnerUpdate, + DateTime? lastPost, + DateTime? lastRootPost, + DateTime? lastVoteTime, + int? lifetimeVoteCount, + List? marketHistory, + String? memoKey, + bool? mined, + String? name, + DateTime? nextVestingWithdrawal, + int? openRecurrentTransfers, + List? otherHistory, + ActiveModel? owner, + int? pendingClaimedAccounts, + int? pendingTransfers, + int? postBandwidth, + int? postCount, + List? postHistory, + String? postVotingPower, + ActiveModel? posting, + UserPostingJsonMetadata? postingJsonMetadata, + int? postingRewards, + DateTime? previousOwnerUpdate, + List? proxiedVsfVotes, + String? proxy, + String? receivedVestingShares, + String? recoveryAccount, + int? reputation, + String? resetAccount, + String? rewardHbdBalance, + String? rewardHiveBalance, + String? rewardVestingBalance, + String? rewardVestingHive, + String? savingsBalance, + String? savingsHbdBalance, + DateTime? savingsHbdLastInterestPayment, + String? savingsHbdSeconds, + DateTime? savingsHbdSecondsLastUpdate, + int? savingsWithdrawRequests, + List? tagsUsage, + int? toWithdraw, + List? transferHistory, + String? vestingBalance, + String? vestingShares, + String? vestingWithdrawRate, + List? voteHistory, + VotingManabarModel? votingManabar, + int? votingPower, + int? withdrawRoutes, + int? withdrawn, + List? witnessVotes, + int? witnessesVotedFor, + }) => + UserModel( + active: active ?? this.active, + balance: balance ?? this.balance, + canVote: canVote ?? this.canVote, + commentCount: commentCount ?? this.commentCount, + created: created ?? this.created, + curationRewards: curationRewards ?? this.curationRewards, + delayedVotes: delayedVotes ?? this.delayedVotes, + delegatedVestingShares: + delegatedVestingShares ?? this.delegatedVestingShares, + downvoteManabar: downvoteManabar ?? this.downvoteManabar, + governanceVoteExpirationTs: + governanceVoteExpirationTs ?? this.governanceVoteExpirationTs, + guestBloggers: guestBloggers ?? this.guestBloggers, + hbdBalance: hbdBalance ?? this.hbdBalance, + hbdLastInterestPayment: + hbdLastInterestPayment ?? this.hbdLastInterestPayment, + hbdSeconds: hbdSeconds ?? this.hbdSeconds, + hbdSecondsLastUpdate: hbdSecondsLastUpdate ?? this.hbdSecondsLastUpdate, + id: id ?? this.id, + jsonMetadata: jsonMetadata ?? this.jsonMetadata, + lastAccountRecovery: lastAccountRecovery ?? this.lastAccountRecovery, + lastAccountUpdate: lastAccountUpdate ?? this.lastAccountUpdate, + lastOwnerUpdate: lastOwnerUpdate ?? this.lastOwnerUpdate, + lastPost: lastPost ?? this.lastPost, + lastRootPost: lastRootPost ?? this.lastRootPost, + lastVoteTime: lastVoteTime ?? this.lastVoteTime, + lifetimeVoteCount: lifetimeVoteCount ?? this.lifetimeVoteCount, + marketHistory: marketHistory ?? this.marketHistory, + memoKey: memoKey ?? this.memoKey, + mined: mined ?? this.mined, + name: name ?? this.name, + nextVestingWithdrawal: + nextVestingWithdrawal ?? this.nextVestingWithdrawal, + openRecurrentTransfers: + openRecurrentTransfers ?? this.openRecurrentTransfers, + otherHistory: otherHistory ?? this.otherHistory, + owner: owner ?? this.owner, + pendingClaimedAccounts: + pendingClaimedAccounts ?? this.pendingClaimedAccounts, + pendingTransfers: pendingTransfers ?? this.pendingTransfers, + postBandwidth: postBandwidth ?? this.postBandwidth, + postCount: postCount ?? this.postCount, + postHistory: postHistory ?? this.postHistory, + postVotingPower: postVotingPower ?? this.postVotingPower, + posting: posting ?? this.posting, + postingJsonMetadata: postingJsonMetadata ?? this.postingJsonMetadata, + postingRewards: postingRewards ?? this.postingRewards, + previousOwnerUpdate: previousOwnerUpdate ?? this.previousOwnerUpdate, + proxiedVsfVotes: proxiedVsfVotes ?? this.proxiedVsfVotes, + proxy: proxy ?? this.proxy, + receivedVestingShares: + receivedVestingShares ?? this.receivedVestingShares, + recoveryAccount: recoveryAccount ?? this.recoveryAccount, + reputation: reputation ?? this.reputation, + resetAccount: resetAccount ?? this.resetAccount, + rewardHbdBalance: rewardHbdBalance ?? this.rewardHbdBalance, + rewardHiveBalance: rewardHiveBalance ?? this.rewardHiveBalance, + rewardVestingBalance: rewardVestingBalance ?? this.rewardVestingBalance, + rewardVestingHive: rewardVestingHive ?? this.rewardVestingHive, + savingsBalance: savingsBalance ?? this.savingsBalance, + savingsHbdBalance: savingsHbdBalance ?? this.savingsHbdBalance, + savingsHbdLastInterestPayment: + savingsHbdLastInterestPayment ?? this.savingsHbdLastInterestPayment, + savingsHbdSeconds: savingsHbdSeconds ?? this.savingsHbdSeconds, + savingsHbdSecondsLastUpdate: + savingsHbdSecondsLastUpdate ?? this.savingsHbdSecondsLastUpdate, + savingsWithdrawRequests: + savingsWithdrawRequests ?? this.savingsWithdrawRequests, + tagsUsage: tagsUsage ?? this.tagsUsage, + toWithdraw: toWithdraw ?? this.toWithdraw, + transferHistory: transferHistory ?? this.transferHistory, + vestingBalance: vestingBalance ?? this.vestingBalance, + vestingShares: vestingShares ?? this.vestingShares, + vestingWithdrawRate: vestingWithdrawRate ?? this.vestingWithdrawRate, + voteHistory: voteHistory ?? this.voteHistory, + votingManabar: votingManabar ?? this.votingManabar, + votingPower: votingPower ?? this.votingPower, + withdrawRoutes: withdrawRoutes ?? this.withdrawRoutes, + withdrawn: withdrawn ?? this.withdrawn, + witnessVotes: witnessVotes ?? this.witnessVotes, + witnessesVotedFor: witnessesVotedFor ?? this.witnessesVotedFor, + ); + + String? get location { + return postingJsonMetadata?.profile?.location; + } + + String? get website { + return postingJsonMetadata?.profile?.website; + } + + factory UserModel.fromJson(Map json) => UserModel( + active: json["active"] == null + ? null + : ActiveModel.fromJson(json["active"]), + balance: asString(json, "balance"), + canVote: json["can_vote"], + commentCount: json["comment_count"], + created: DateTime.parse(json["created"]), + curationRewards: json["curation_rewards"], + delayedVotes: json["delayed_votes"] == null + ? [] + : List.from(json["delayed_votes"]! + .map((x) => DelayedVoteModel.fromJson(x))), + delegatedVestingShares: json["delegated_vesting_shares"], + downvoteManabar: json["downvote_manabar"] == null + ? null + : DownvoteManabarModel.fromJson(json["downvote_manabar"]), + governanceVoteExpirationTs: + json["governance_vote_expiration_ts"] == null + ? null + : DateTime.parse(json["governance_vote_expiration_ts"]), + guestBloggers: json["guest_bloggers"] == null + ? [] + : List.from(json["guest_bloggers"]!.map((x) => x)), + hbdBalance: asString(json, "hbd_balance"), + hbdLastInterestPayment: json["hbd_last_interest_payment"] == null + ? null + : DateTime.parse(json["hbd_last_interest_payment"]), + hbdSeconds: json["hbd_seconds"], + hbdSecondsLastUpdate: json["hbd_seconds_last_update"] == null + ? null + : DateTime.parse(json["hbd_seconds_last_update"]), + id: json["id"], + jsonMetadata: json["json_metadata"], + lastAccountRecovery: json["last_account_recovery"] == null + ? null + : DateTime.parse(json["last_account_recovery"]), + lastAccountUpdate: json["last_account_update"] == null + ? null + : DateTime.parse(json["last_account_update"]), + lastOwnerUpdate: json["last_owner_update"] == null + ? null + : DateTime.parse(json["last_owner_update"]), + lastPost: json["last_post"] == null + ? null + : DateTime.parse(json["last_post"]), + lastRootPost: json["last_root_post"] == null + ? null + : DateTime.parse(json["last_root_post"]), + lastVoteTime: json["last_vote_time"] == null + ? null + : DateTime.parse(json["last_vote_time"]), + lifetimeVoteCount: json["lifetime_vote_count"], + marketHistory: json["market_history"] == null + ? [] + : List.from(json["market_history"]!.map((x) => x)), + memoKey: json["memo_key"], + mined: json["mined"], + name: json["name"], + nextVestingWithdrawal: json["next_vesting_withdrawal"] == null + ? null + : DateTime.parse(json["next_vesting_withdrawal"]), + openRecurrentTransfers: json["open_recurrent_transfers"], + otherHistory: json["other_history"] == null + ? [] + : List.from(json["other_history"]!.map((x) => x)), + owner: + json["owner"] == null ? null : ActiveModel.fromJson(json["owner"]), + pendingClaimedAccounts: json["pending_claimed_accounts"], + pendingTransfers: json["pending_transfers"], + postBandwidth: json["post_bandwidth"], + postCount: json["post_count"], + postHistory: json["post_history"] == null + ? [] + : List.from(json["post_history"]!.map((x) => x)), + postVotingPower: json["post_voting_power"], + posting: json["posting"] == null + ? null + : ActiveModel.fromJson(json["posting"]), + postingJsonMetadata: json["posting_json_metadata"].isNotEmpty + ? UserPostingJsonMetadata.fromRawJson(json["posting_json_metadata"]) + : null, + postingRewards: json["posting_rewards"], + previousOwnerUpdate: json["previous_owner_update"] == null + ? null + : DateTime.parse(json["previous_owner_update"]), + proxiedVsfVotes: json["proxied_vsf_votes"] == null + ? [] + : List.from(json["proxied_vsf_votes"]!.map((x) { + if (x is String) { + return int.parse(x); + } else { + return x; + } + })), + proxy: json["proxy"], + receivedVestingShares: json["received_vesting_shares"], + recoveryAccount: json["recovery_account"], + reputation: json["reputation"], + resetAccount: json["reset_account"], + rewardHbdBalance: json["reward_hbd_balance"], + rewardHiveBalance: json["reward_hive_balance"], + rewardVestingBalance: json["reward_vesting_balance"], + rewardVestingHive: json["reward_vesting_hive"], + savingsBalance: json["savings_balance"], + savingsHbdBalance: json["savings_hbd_balance"], + savingsHbdLastInterestPayment: + json["savings_hbd_last_interest_payment"] == null + ? null + : DateTime.parse(json["savings_hbd_last_interest_payment"]), + savingsHbdSeconds: json["savings_hbd_seconds"], + savingsHbdSecondsLastUpdate: + json["savings_hbd_seconds_last_update"] == null + ? null + : DateTime.parse(json["savings_hbd_seconds_last_update"]), + savingsWithdrawRequests: json["savings_withdraw_requests"], + tagsUsage: json["tags_usage"] == null + ? [] + : List.from(json["tags_usage"]!.map((x) => x)), + toWithdraw: json["to_withdraw"], + transferHistory: json["transfer_history"] == null + ? [] + : List.from(json["transfer_history"]!.map((x) => x)), + vestingBalance: json["vesting_balance"], + vestingShares: json["vesting_shares"], + vestingWithdrawRate: json["vesting_withdraw_rate"], + voteHistory: json["vote_history"] == null + ? [] + : List.from(json["vote_history"]!.map((x) => x)), + votingManabar: json["voting_manabar"] == null + ? null + : VotingManabarModel.fromJson(json["voting_manabar"]), + votingPower: json["voting_power"], + withdrawRoutes: json["withdraw_routes"], + withdrawn: json["withdrawn"], + witnessVotes: json["witness_votes"] == null + ? [] + : List.from(json["witness_votes"]!.map((x) => x)), + witnessesVotedFor: json["witnesses_voted_for"], + ); + + Map toJson() => { + "active": active?.toJson(), + "balance": balance, + "can_vote": canVote, + "comment_count": commentCount, + "created": created.toIso8601String(), + "curation_rewards": curationRewards, + "delayed_votes": delayedVotes == null + ? [] + : List.from(delayedVotes!.map((x) => x.toJson())), + "delegated_vesting_shares": delegatedVestingShares, + "downvote_manabar": downvoteManabar?.toJson(), + "governance_vote_expiration_ts": + governanceVoteExpirationTs?.toIso8601String(), + "guest_bloggers": guestBloggers == null + ? [] + : List.from(guestBloggers!.map((x) => x)), + "hbd_balance": hbdBalance, + "hbd_last_interest_payment": hbdLastInterestPayment?.toIso8601String(), + "hbd_seconds": hbdSeconds, + "hbd_seconds_last_update": hbdSecondsLastUpdate?.toIso8601String(), + "id": id, + "json_metadata": jsonMetadata, + "last_account_recovery": lastAccountRecovery?.toIso8601String(), + "last_account_update": lastAccountUpdate?.toIso8601String(), + "last_owner_update": lastOwnerUpdate?.toIso8601String(), + "last_post": lastPost?.toIso8601String(), + "last_root_post": lastRootPost?.toIso8601String(), + "last_vote_time": lastVoteTime?.toIso8601String(), + "lifetime_vote_count": lifetimeVoteCount, + "market_history": marketHistory == null + ? [] + : List.from(marketHistory!.map((x) => x)), + "memo_key": memoKey, + "mined": mined, + "name": name, + "next_vesting_withdrawal": nextVestingWithdrawal?.toIso8601String(), + "open_recurrent_transfers": openRecurrentTransfers, + "other_history": otherHistory == null + ? [] + : List.from(otherHistory!.map((x) => x)), + "owner": owner?.toJson(), + "pending_claimed_accounts": pendingClaimedAccounts, + "pending_transfers": pendingTransfers, + "post_bandwidth": postBandwidth, + "post_count": postCount, + "post_history": postHistory == null + ? [] + : List.from(postHistory!.map((x) => x)), + "post_voting_power": postVotingPower, + "posting": posting?.toJson(), + "posting_json_metadata": postingJsonMetadata?.toJson(), + "posting_rewards": postingRewards, + "previous_owner_update": previousOwnerUpdate?.toIso8601String(), + "proxied_vsf_votes": proxiedVsfVotes == null + ? [] + : List.from(proxiedVsfVotes!.map((x) => x)), + "proxy": proxy, + "received_vesting_shares": receivedVestingShares, + "recovery_account": recoveryAccount, + "reputation": reputation, + "reset_account": resetAccount, + "reward_hbd_balance": rewardHbdBalance, + "reward_hive_balance": rewardHiveBalance, + "reward_vesting_balance": rewardVestingBalance, + "reward_vesting_hive": rewardVestingHive, + "savings_balance": savingsBalance, + "savings_hbd_balance": savingsHbdBalance, + "savings_hbd_last_interest_payment": + savingsHbdLastInterestPayment?.toIso8601String(), + "savings_hbd_seconds": savingsHbdSeconds, + "savings_hbd_seconds_last_update": + savingsHbdSecondsLastUpdate?.toIso8601String(), + "savings_withdraw_requests": savingsWithdrawRequests, + "tags_usage": tagsUsage == null + ? [] + : List.from(tagsUsage!.map((x) => x)), + "to_withdraw": toWithdraw, + "transfer_history": transferHistory == null + ? [] + : List.from(transferHistory!.map((x) => x)), + "vesting_balance": vestingBalance, + "vesting_shares": vestingShares, + "vesting_withdraw_rate": vestingWithdrawRate, + "vote_history": voteHistory == null + ? [] + : List.from(voteHistory!.map((x) => x)), + "voting_manabar": votingManabar?.toJson(), + "voting_power": votingPower, + "withdraw_routes": withdrawRoutes, + "withdrawn": withdrawn, + "witness_votes": witnessVotes == null + ? [] + : List.from(witnessVotes!.map((x) => x)), + "witnesses_voted_for": witnessesVotedFor, + }; +} diff --git a/lib/src/models/user_account/voting_manabar_model.dart b/lib/src/models/user_account/voting_manabar_model.dart new file mode 100644 index 00000000..c73905d2 --- /dev/null +++ b/lib/src/models/user_account/voting_manabar_model.dart @@ -0,0 +1,28 @@ +class VotingManabarModel { + final int? currentMana; + final int? lastUpdateTime; + + VotingManabarModel({ + this.currentMana, + this.lastUpdateTime, + }); + + VotingManabarModel copyWith({ + int? currentMana, + int? lastUpdateTime, + }) => + VotingManabarModel( + currentMana: currentMana ?? this.currentMana, + lastUpdateTime: lastUpdateTime ?? this.lastUpdateTime, + ); + + factory VotingManabarModel.fromJson(Map json) => VotingManabarModel( + currentMana: json["current_mana"], + lastUpdateTime: json["\"last_update_time"], + ); + + Map toJson() => { + "current_mana": currentMana, + "\"last_update_time": lastUpdateTime, + }; +} diff --git a/lib/src/screens/home_screen/home_screen_feed_list.dart b/lib/src/screens/home_screen/home_screen_feed_list.dart index 2a00ce84..7ed8bd99 100644 --- a/lib/src/screens/home_screen/home_screen_feed_list.dart +++ b/lib/src/screens/home_screen/home_screen_feed_list.dart @@ -149,44 +149,51 @@ class _HomeScreenFeedListState extends State } void loadFeed(bool reset) async { - log('loading'); - if (isLoading) return; - if (!firstPageLoaded) { - setState(() { - isLoading = true; - firstPageLoaded = false; - }); - var newItems = await loadWith(true); - setState(() { - if (newItems.length < pageLimit - 1) { - isPageEnded = true; - } - items = newItems; - if (items.isEmpty && widget.onEmptyDataCallback != null) { - widget.onEmptyDataCallback!(); - } - isLoading = false; - firstPageLoaded = true; - }); - } else { - setState(() { - isLoading = true; - if (reset) { + try { + log('loading'); + if (isLoading) return; + if (!firstPageLoaded) { + setState(() { + isLoading = true; firstPageLoaded = false; - isPageEnded = false; - } - }); - var newItems = await loadWith(reset); + }); + var newItems = await loadWith(true); + setState(() { + if (newItems.length < pageLimit - 1) { + isPageEnded = true; + } + items = newItems; + if (items.isEmpty && widget.onEmptyDataCallback != null) { + widget.onEmptyDataCallback!(); + } + isLoading = false; + firstPageLoaded = true; + }); + } else { + setState(() { + isLoading = true; + if (reset) { + firstPageLoaded = false; + isPageEnded = false; + } + }); + var newItems = await loadWith(reset); + setState(() { + if (newItems.length < pageLimit - 1) { + isPageEnded = true; + } + if (newItems.isNotEmpty) { + newItems.removeAt(0); + } + items = items + newItems; + isLoading = false; + firstPageLoaded = true; + }); + } + } catch (e) { setState(() { - if (newItems.length < pageLimit - 1) { - isPageEnded = true; - } - if (newItems.isNotEmpty) { - newItems.removeAt(0); - } - items = items + newItems; isLoading = false; - firstPageLoaded = true; + hasFailed = true; }); } } @@ -222,7 +229,9 @@ class _HomeScreenFeedListState extends State textAlign: TextAlign.center, ), ), - const SizedBox(height: 5,), + const SizedBox( + height: 5, + ), ElevatedButton( onPressed: () { loadFeed(true); diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index de406e79..e93160e1 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -4,8 +4,9 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; +import 'package:acela/src/models/user_account/action_response.dart'; +import 'package:acela/src/models/user_account/user_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/screens/home_screen/new_home_screen.dart'; import 'package:acela/src/screens/login/sign_up_screen.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/graphql/gql_communicator.dart'; @@ -341,39 +342,56 @@ class _HiveAuthLoginScreenState extends State var bridgeResponse = LoginBridgeResponse.fromJsonString(response); if (bridgeResponse.valid) { debugPrint("Successful login"); - String resolution = await storage.read(key: 'resolution') ?? '480p'; - String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - String union = await storage.read(key: 'union') ?? - GQLCommunicator.defaultGQLServer; - String? lang = await storage.read(key: 'lang'); - await storage.write(key: 'username', value: usernameController.text); - await storage.write(key: 'postingKey', value: postingKey); - await storage.delete(key: 'hasId'); - await storage.delete(key: 'hasExpiry'); - await storage.delete(key: 'hasAuthKey'); - await storage.delete(key: 'cookie'); - var data = HiveUserData( - accessToken: null, - postingAuthority: null, - username: usernameController.text, - postingKey: postingKey, - keychainData: null, - cookie: null, - resolution: resolution, - rpc: rpc, - union: union, - loaded: true, - language: lang, - ); - server.updateHiveUserData(data); - var cookie = await Communicator().getValidCookie(data); - log(cookie); - Navigator.of(context).pop(); - showMessage( - 'You have successfully logged in as - ${usernameController.text}'); - setState(() { - isLoading = false; - }); + ActionSingleDataResponse response = + await Communicator().getAccountInfo(usernameController.text); + if (response.isSuccess) { + if (response.data!.hasThreeSpeakPostingAuthority()) { + String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + String union = await storage.read(key: 'union') ?? + GQLCommunicator.defaultGQLServer; + String? lang = await storage.read(key: 'lang'); + await storage.write( + key: 'username', value: usernameController.text); + await storage.write(key: 'postingKey', value: postingKey); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); + await storage.delete(key: 'cookie'); + var data = HiveUserData( + accessToken: null, + postingAuthority: null, + username: usernameController.text, + postingKey: postingKey, + keychainData: null, + cookie: null, + resolution: resolution, + rpc: rpc, + union: union, + loaded: true, + language: lang, + ); + server.updateHiveUserData(data); + var cookie = await Communicator().getValidCookie(data); + log(cookie); + Navigator.of(context).pop(); + showMessage( + 'You have successfully logged in as - ${usernameController.text}'); + setState(() { + isLoading = false; + }); + } else { + showMessage("Three speak posting authority is required to log in"); + setState(() { + isLoading = false; + }); + } + } else { + showMessage("Server error"); + setState(() { + isLoading = false; + }); + } } else { // it is NO valid key showError('Not valid key.'); @@ -386,7 +404,8 @@ class _HiveAuthLoginScreenState extends State isLoading = false; }); log(e.toString()); - if(e == 'No 3Speak Account found with name - ${usernameController.text}'){ + if (e == + 'No 3Speak Account found with name - ${usernameController.text}') { await storage.delete(key: 'username'); await storage.delete(key: 'postingKey'); await storage.delete(key: 'hasId'); @@ -397,7 +416,7 @@ class _HiveAuthLoginScreenState extends State username: null, postingKey: null, keychainData: null, - cookie: null, + cookie: null, accessToken: null, postingAuthority: null, resolution: '480p', @@ -434,34 +453,51 @@ class _HiveAuthLoginScreenState extends State showMessage( 'Did not find token & expiry details from HiveAuth. Please go back & try again.'); } else { - const storage = FlutterSecureStorage(); - await storage.write(key: 'username', value: usernameController.text); - await storage.delete(key: 'postingKey'); - await storage.delete(key: 'cookie'); - await storage.write(key: 'hasId', value: tokenData[0]); - await storage.write(key: 'hasExpiry', value: tokenData[1]); - await storage.write(key: 'hasAuthKey', value: authKey); - var newData = HiveUserData( - username: usernameController.text, - postingKey: null, - keychainData: HiveKeychainData( - hasAuthKey: authKey, - hasExpiry: tokenData[1], - hasId: tokenData[0], - ), - cookie: null, - accessToken: null, - postingAuthority: null, - resolution: data.resolution, - rpc: data.rpc, - union: data.union, - loaded: true, - language: data.language, - ); - server.updateHiveUserData(newData); - showMessage( - 'You have successfully logged in with Hive Auth with user - ${usernameController.text}'); - Navigator.of(context).pop(); + ActionSingleDataResponse response = + await Communicator().getAccountInfo(usernameController.text); + if (response.isSuccess) { + if (response.data!.hasThreeSpeakPostingAuthority()) { + const storage = FlutterSecureStorage(); + await storage.write( + key: 'username', value: usernameController.text); + await storage.delete(key: 'postingKey'); + await storage.delete(key: 'cookie'); + await storage.write(key: 'hasId', value: tokenData[0]); + await storage.write(key: 'hasExpiry', value: tokenData[1]); + await storage.write(key: 'hasAuthKey', value: authKey); + var newData = HiveUserData( + username: usernameController.text, + postingKey: null, + keychainData: HiveKeychainData( + hasAuthKey: authKey, + hasExpiry: tokenData[1], + hasId: tokenData[0], + ), + cookie: null, + accessToken: null, + postingAuthority: null, + resolution: data.resolution, + rpc: data.rpc, + union: data.union, + loaded: true, + language: data.language, + ); + server.updateHiveUserData(newData); + showMessage( + 'You have successfully logged in with Hive Auth with user - ${usernameController.text}'); + Navigator.of(context).pop(); + } else { + setState(() { + isLoading = false; + }); + showMessage("Three speak posting authority is required to log in"); + } + } else { + setState(() { + isLoading = false; + }); + showMessage("Server error"); + } } } else { showMessage( diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index 47ab474e..e34e6e69 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -11,6 +11,8 @@ import 'package:acela/src/models/home_screen_feed_models/home_feed.dart'; import 'package:acela/src/models/login/memo_response.dart'; import 'package:acela/src/models/my_account/video_ops.dart'; import 'package:acela/src/models/podcast/upload/podcast_episode_upload_response.dart'; +import 'package:acela/src/models/user_account/action_response.dart'; +import 'package:acela/src/models/user_account/user_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/models/video_details_model/video_details.dart'; import 'package:acela/src/models/video_upload/does_post_exists.dart'; @@ -817,4 +819,22 @@ class Communicator { return ActionResponse(data: '', valid: false, error: e.toString()); } } + + Future> getAccountInfo( + String accountName) async { + try { + final String jsonString = await MethodChannel('com.example.acela/auth') + .invokeMethod('getAccountInfo', { + 'username': accountName, + }); + + ActionSingleDataResponse response = + ActionSingleDataResponse.fromJsonString( + jsonString, UserModel.fromJson); + return response; + } catch (e) { + return ActionSingleDataResponse( + status: ResponseStatus.failed, errorMessage: e.toString()); + } + } } diff --git a/lib/src/widgets/retry.dart b/lib/src/widgets/retry.dart index 401ee02b..abbcecb2 100644 --- a/lib/src/widgets/retry.dart +++ b/lib/src/widgets/retry.dart @@ -14,6 +14,8 @@ class RetryScreen extends StatelessWidget { Widget build(BuildContext context) { return Center( child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton(onPressed: onRetry, child: const Text('Retry')), Text(error) diff --git a/pubspec.lock b/pubspec.lock index 87ec36e7..26d72df1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: "1639d96851f9e9e215dd39c9baad56846488aef3df392cb3221f37f70beac686" + sha256: "3dee3db3468c5f4640a4e8aa9c1e22561c298976d8c39ed2fdd456a9a3db26e1" url: "https://pub.dev" source: hosted - version: "1.3.31" + version: "1.3.32" adaptive_action_sheet: dependency: "direct main" description: @@ -527,26 +527,26 @@ packages: dependency: "direct main" description: name: firebase_analytics - sha256: f3d82590042a5fc0470ea47d3350dc0f2ab12269437178f36e0e519d46992439 + sha256: c56bcc7abc6caacc33e8495bc604a5861d25ce371f1b06476ae226e7cbb21d4c url: "https://pub.dev" source: hosted - version: "10.10.3" + version: "10.10.4" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - sha256: "58ebb93af882c5290514e9157e90035c0ccf8e559a16c17331da7b3d6fb9e8f5" + sha256: e8cdb845820eaa5f1d29de31a72aab8addbbffc6483f1e5123a9d0b611735285 url: "https://pub.dev" source: hosted - version: "3.10.4" + version: "3.10.5" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - sha256: "578babefa09ddc92d088c08f5320cd160ef73b03e17fe1d95e43d90fed253b7f" + sha256: e2fabebdf16bb99506a1e7e84f5effd6313c90678e6ea1876d301f057483a198 url: "https://pub.dev" source: hosted - version: "0.5.7+3" + version: "0.5.7+4" firebase_core: dependency: "direct main" description: @@ -575,18 +575,18 @@ packages: dependency: "direct main" description: name: firebase_crashlytics - sha256: b3e1eadbf37ec2062eba290f183db750f809ed6e7ffae8af9def67394645aec1 + sha256: "1c499d1d97b93d24aee099259f89a5fbd6ce7d11d0fe98824586087f1291931b" url: "https://pub.dev" source: hosted - version: "3.5.3" + version: "3.5.4" firebase_crashlytics_platform_interface: dependency: transitive description: name: firebase_crashlytics_platform_interface - sha256: e9a90f5c033fb77ed4dbebabf07aeb52502c581fca5fdc332edccc71f0557a47 + sha256: "3160d049c220422f8de34690c39be42af8309a030d9dd370051582272181238e" url: "https://pub.dev" source: hosted - version: "3.6.31" + version: "3.6.32" fixnum: dependency: transitive description: From 8beb7f2fc80504577a01e9a8483b8e2e59a316bd Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 2 May 2024 17:23:54 +0530 Subject: [PATCH 405/466] 2 bugs fixed --- lib/src/screens/my_account/update_video/video_details_info.dart | 1 + .../upload/video/widgets/uploadProgressExpansionTile.dart | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index a43f399c..0c1850ec 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -112,6 +112,7 @@ class _VideoDetailsInfoState extends State { beneficiaries = widget.item.benes; tagsController.text = widget.item.tags.isEmpty ? "threespeak,mobile" : widget.item.tags; + tags = widget.item.tags.isEmpty ? "threespeak,mobile" : widget.item.tags; socket = WebSocketChannel.connect( Uri.parse(Communicator.hiveAuthServer), ); diff --git a/lib/src/screens/upload/video/widgets/uploadProgressExpansionTile.dart b/lib/src/screens/upload/video/widgets/uploadProgressExpansionTile.dart index 9b248d02..462c9b0a 100644 --- a/lib/src/screens/upload/video/widgets/uploadProgressExpansionTile.dart +++ b/lib/src/screens/upload/video/widgets/uploadProgressExpansionTile.dart @@ -151,7 +151,7 @@ class _UploadProgressExpandableTileState visible: showWidgets, child: ListTile( leading: moveWidgetToEncodingQueueProgressWidget(!isExpanded), - title: const Text('Pinning to IPFS'), + title: const Text('Preparing for Encoding'), trailing: moveWidgetToEncodingQueueProgressWidget(isExpanded)), ), Visibility( From 9fefa0f772e6b38595956f3c1a519f76bfd2a34a Mon Sep 17 00:00:00 2001 From: Sagar Date: Thu, 2 May 2024 17:27:28 +0530 Subject: [PATCH 406/466] posting authority check before video upload starts, removed posting authority check from login --- lib/src/screens/login/ha_login_screen.dart | 163 +++++++----------- .../upload/video/mixins/video_save_mixin.dart | 2 +- .../upload/video/video_upload_screen.dart | 47 +++-- 3 files changed, 96 insertions(+), 116 deletions(-) diff --git a/lib/src/screens/login/ha_login_screen.dart b/lib/src/screens/login/ha_login_screen.dart index e93160e1..a290d463 100644 --- a/lib/src/screens/login/ha_login_screen.dart +++ b/lib/src/screens/login/ha_login_screen.dart @@ -4,8 +4,6 @@ import 'dart:developer'; import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; -import 'package:acela/src/models/user_account/action_response.dart'; -import 'package:acela/src/models/user_account/user_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/login/sign_up_screen.dart'; import 'package:acela/src/utils/communicator.dart'; @@ -342,56 +340,39 @@ class _HiveAuthLoginScreenState extends State var bridgeResponse = LoginBridgeResponse.fromJsonString(response); if (bridgeResponse.valid) { debugPrint("Successful login"); - ActionSingleDataResponse response = - await Communicator().getAccountInfo(usernameController.text); - if (response.isSuccess) { - if (response.data!.hasThreeSpeakPostingAuthority()) { - String resolution = await storage.read(key: 'resolution') ?? '480p'; - String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; - String union = await storage.read(key: 'union') ?? - GQLCommunicator.defaultGQLServer; - String? lang = await storage.read(key: 'lang'); - await storage.write( - key: 'username', value: usernameController.text); - await storage.write(key: 'postingKey', value: postingKey); - await storage.delete(key: 'hasId'); - await storage.delete(key: 'hasExpiry'); - await storage.delete(key: 'hasAuthKey'); - await storage.delete(key: 'cookie'); - var data = HiveUserData( - accessToken: null, - postingAuthority: null, - username: usernameController.text, - postingKey: postingKey, - keychainData: null, - cookie: null, - resolution: resolution, - rpc: rpc, - union: union, - loaded: true, - language: lang, - ); - server.updateHiveUserData(data); - var cookie = await Communicator().getValidCookie(data); - log(cookie); - Navigator.of(context).pop(); - showMessage( - 'You have successfully logged in as - ${usernameController.text}'); - setState(() { - isLoading = false; - }); - } else { - showMessage("Three speak posting authority is required to log in"); - setState(() { - isLoading = false; - }); - } - } else { - showMessage("Server error"); - setState(() { - isLoading = false; - }); - } + String resolution = await storage.read(key: 'resolution') ?? '480p'; + String rpc = await storage.read(key: 'rpc') ?? 'api.hive.blog'; + String union = await storage.read(key: 'union') ?? + GQLCommunicator.defaultGQLServer; + String? lang = await storage.read(key: 'lang'); + await storage.write(key: 'username', value: usernameController.text); + await storage.write(key: 'postingKey', value: postingKey); + await storage.delete(key: 'hasId'); + await storage.delete(key: 'hasExpiry'); + await storage.delete(key: 'hasAuthKey'); + await storage.delete(key: 'cookie'); + var data = HiveUserData( + accessToken: null, + postingAuthority: null, + username: usernameController.text, + postingKey: postingKey, + keychainData: null, + cookie: null, + resolution: resolution, + rpc: rpc, + union: union, + loaded: true, + language: lang, + ); + server.updateHiveUserData(data); + var cookie = await Communicator().getValidCookie(data); + log(cookie); + Navigator.of(context).pop(); + showMessage( + 'You have successfully logged in as - ${usernameController.text}'); + setState(() { + isLoading = false; + }); } else { // it is NO valid key showError('Not valid key.'); @@ -404,8 +385,7 @@ class _HiveAuthLoginScreenState extends State isLoading = false; }); log(e.toString()); - if (e == - 'No 3Speak Account found with name - ${usernameController.text}') { + if(e == 'No 3Speak Account found with name - ${usernameController.text}'){ await storage.delete(key: 'username'); await storage.delete(key: 'postingKey'); await storage.delete(key: 'hasId'); @@ -416,7 +396,7 @@ class _HiveAuthLoginScreenState extends State username: null, postingKey: null, keychainData: null, - cookie: null, + cookie: null, accessToken: null, postingAuthority: null, resolution: '480p', @@ -453,51 +433,34 @@ class _HiveAuthLoginScreenState extends State showMessage( 'Did not find token & expiry details from HiveAuth. Please go back & try again.'); } else { - ActionSingleDataResponse response = - await Communicator().getAccountInfo(usernameController.text); - if (response.isSuccess) { - if (response.data!.hasThreeSpeakPostingAuthority()) { - const storage = FlutterSecureStorage(); - await storage.write( - key: 'username', value: usernameController.text); - await storage.delete(key: 'postingKey'); - await storage.delete(key: 'cookie'); - await storage.write(key: 'hasId', value: tokenData[0]); - await storage.write(key: 'hasExpiry', value: tokenData[1]); - await storage.write(key: 'hasAuthKey', value: authKey); - var newData = HiveUserData( - username: usernameController.text, - postingKey: null, - keychainData: HiveKeychainData( - hasAuthKey: authKey, - hasExpiry: tokenData[1], - hasId: tokenData[0], - ), - cookie: null, - accessToken: null, - postingAuthority: null, - resolution: data.resolution, - rpc: data.rpc, - union: data.union, - loaded: true, - language: data.language, - ); - server.updateHiveUserData(newData); - showMessage( - 'You have successfully logged in with Hive Auth with user - ${usernameController.text}'); - Navigator.of(context).pop(); - } else { - setState(() { - isLoading = false; - }); - showMessage("Three speak posting authority is required to log in"); - } - } else { - setState(() { - isLoading = false; - }); - showMessage("Server error"); - } + const storage = FlutterSecureStorage(); + await storage.write(key: 'username', value: usernameController.text); + await storage.delete(key: 'postingKey'); + await storage.delete(key: 'cookie'); + await storage.write(key: 'hasId', value: tokenData[0]); + await storage.write(key: 'hasExpiry', value: tokenData[1]); + await storage.write(key: 'hasAuthKey', value: authKey); + var newData = HiveUserData( + username: usernameController.text, + postingKey: null, + keychainData: HiveKeychainData( + hasAuthKey: authKey, + hasExpiry: tokenData[1], + hasId: tokenData[0], + ), + cookie: null, + accessToken: null, + postingAuthority: null, + resolution: data.resolution, + rpc: data.rpc, + union: data.union, + loaded: true, + language: data.language, + ); + server.updateHiveUserData(newData); + showMessage( + 'You have successfully logged in with Hive Auth with user - ${usernameController.text}'); + Navigator.of(context).pop(); } } else { showMessage( diff --git a/lib/src/screens/upload/video/mixins/video_save_mixin.dart b/lib/src/screens/upload/video/mixins/video_save_mixin.dart index 19067438..648d05e5 100644 --- a/lib/src/screens/upload/video/mixins/video_save_mixin.dart +++ b/lib/src/screens/upload/video/mixins/video_save_mixin.dart @@ -30,7 +30,7 @@ class VideoSaveMixin { user: user, videoId: item.id, title: title, - description: description, + description: "${description} Uploaded using 3Speak Mobile App", isNsfwContent: isNsfwContent, tags: tags, thumbnail: thumbIpfs.isEmpty ? null : thumbIpfs, diff --git a/lib/src/screens/upload/video/video_upload_screen.dart b/lib/src/screens/upload/video/video_upload_screen.dart index fcfc5955..5b6d44a5 100644 --- a/lib/src/screens/upload/video/video_upload_screen.dart +++ b/lib/src/screens/upload/video/video_upload_screen.dart @@ -1,5 +1,7 @@ import 'dart:io'; +import 'package:acela/src/models/user_account/action_response.dart'; +import 'package:acela/src/models/user_account/user_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/my_account/my_account_screen.dart'; import 'package:acela/src/screens/upload/video/controller/video_upload_controller.dart'; @@ -12,6 +14,7 @@ import 'package:acela/src/screens/upload/video/widgets/uploadProgressExpansionTi import 'package:acela/src/screens/upload/video/widgets/upload_textfield.dart'; import 'package:acela/src/screens/upload/video/widgets/video_upload_divider.dart'; import 'package:acela/src/screens/upload/video/widgets/work_type_widget.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/enum.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; @@ -214,29 +217,43 @@ class _VideoUploadScreenState extends State { controller.jumpToPage(); if (controller.uploadStatus.value == UploadStatus.idle) { try { - final XFile? file; - // file = null; - file = await ImagePicker().pickVideo( - source: widget.isCamera ? ImageSource.camera : ImageSource.gallery, - preferredCameraDevice: CameraDevice.front, - ); + ActionSingleDataResponse response = + await Communicator().getAccountInfo(widget.appData.username!); + if (response.isSuccess) { + if (response.data!.hasThreeSpeakPostingAuthority()) { + final XFile? file; + // file = null; + file = await ImagePicker().pickVideo( + source: + widget.isCamera ? ImageSource.camera : ImageSource.gallery, + preferredCameraDevice: CameraDevice.front, + ); - if (file != null) { - var fileToSave = File(file.path); - if (widget.isCamera) { - ImagesPicker.saveVideoToAlbum(fileToSave); + if (file != null) { + var fileToSave = File(file.path); + if (widget.isCamera) { + ImagesPicker.saveVideoToAlbum(fileToSave); + } + controller.onUpload( + hiveUserData: widget.appData, + pickedVideoFile: file, + ); + } else { + showMessage('Video Picker Cancelled'); + Navigator.pop(context); + } + } else { + Navigator.pop(context); + showMessage("Three speak posting authority is required to upload video"); } - controller.onUpload( - hiveUserData: widget.appData, - pickedVideoFile: file, - ); } else { - showMessage('Video Picker Cancelled'); Navigator.pop(context); + showMessage("Server error,please try again"); } } catch (e) { showMessage(e.toString()); Navigator.pop(context); + controller.resetController(); } } } From f37b01c393cbfb36e9671838d5160b402caf06f5 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Thu, 2 May 2024 18:19:15 +0530 Subject: [PATCH 407/466] added bridge on iOS side for getAccountInfo --- ios/Runner/AcelaWebViewController.swift | 13 +++++++++++++ ios/Runner/Bridges/Auth/AuthBridge.swift | 12 ++++++++++++ ios/Runner/public/index.html | 17 ++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index b5c855ce..ed90d79e 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -30,6 +30,7 @@ class AcelaWebViewController: UIViewController { var getEncryptedChallengeHandler: ((String) -> Void)? = nil var getDecryptedChallengeHandler: ((String) -> Void)? = nil var doWeHavePostingAuthHandler: ((String) -> Void)? = nil + var getAccountInfoHandler: ((String) -> Void)? = nil override func viewDidLoad() { super.viewDidLoad() @@ -168,6 +169,13 @@ class AcelaWebViewController: UIViewController { } } + func getAccountInfo(username: String, handler: @escaping (String) -> Void) { + getAccountInfoHandler = handler + OperationQueue.main.addOperation { + self.webView?.evaluateJavaScript("getAccountInfo('\(username)');") + } + } + func postPodcast( thumbnail: String, enclosureUrl: String, @@ -319,6 +327,11 @@ extension AcelaWebViewController: WKScriptMessageHandler { let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) else { return } getDecryptedChallengeHandler?(response) + case "getAccountInfo": + guard + let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) + else { return } + getAccountInfoHandler?(response) case "doWeHavePostingAuth": guard let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) diff --git a/ios/Runner/Bridges/Auth/AuthBridge.swift b/ios/Runner/Bridges/Auth/AuthBridge.swift index ccc6e0a1..6e071e18 100644 --- a/ios/Runner/Bridges/Auth/AuthBridge.swift +++ b/ios/Runner/Bridges/Auth/AuthBridge.swift @@ -231,6 +231,18 @@ class AuthBridge { acela.commentOnContent(user: user, author: author, permlink: permlink, comment: comment, postingKey: postingKey, hasKey: hasKey, hasAuthKey: hasAuthKey) { response in result(response) } + case "getAccountInfo": + guard + let arguments = call.arguments as? NSDictionary, + let username = arguments["username"] as? String, + let acela = acela + else { + result(FlutterMethodNotImplemented) + return + } + acela.getAccountInfo(username: username) { response in + result(response) + } default: debugPrint("do nothing") } }) diff --git a/ios/Runner/public/index.html b/ios/Runner/public/index.html index d83a9e11..c28d7854 100644 --- a/ios/Runner/public/index.html +++ b/ios/Runner/public/index.html @@ -70,7 +70,9 @@ async function validateHiveKey(accountName, postingKey) { try { - const accounts = await dhiveClient.database.getAccounts([accountName]); + const accounts = await dhiveClient.database.getAccounts([ + accountName, + ]); const pubWif = accounts[0].posting.key_auths[0][0]; console.log("PubWif: ", pubWif); const pKey = dhive.PrivateKey.fromString(postingKey) @@ -719,6 +721,19 @@ } } + async function getAccountInfo(accountName) { + const response = await dhiveClient.database.call("get_accounts", [ + [accountName], + ]); + replyToNative({ + id: "identifier", + type: "getAccountInfo", + data: response[0], + valid: true, + error: "", + }); + } + function getEncryptedChallenge(username, authKey) { try { const challenge_data = { From a66fa1c94a22c344d16fc9d182acfa494aa13c75 Mon Sep 17 00:00:00 2001 From: Sagar Date: Fri, 3 May 2024 13:59:45 +0530 Subject: [PATCH 408/466] safe area, podcast image, podcast pop screen fix --- lib/src/models/podcast/podcast_episodes.dart | 13 + .../podcast/trending_podcast_response.dart | 3 + .../widgets/bottom_nav_bar.dart | 26 +- .../controller/podcast_player_controller.dart | 2 +- .../podcast_episodes_view.dart | 4 +- .../podcast/view/podcast_trending.dart | 53 +-- .../new_pod_cast_epidose_player.dart | 364 +++++++++--------- 7 files changed, 247 insertions(+), 218 deletions(-) diff --git a/lib/src/models/podcast/podcast_episodes.dart b/lib/src/models/podcast/podcast_episodes.dart index a333d079..cebd2afe 100644 --- a/lib/src/models/podcast/podcast_episodes.dart +++ b/lib/src/models/podcast/podcast_episodes.dart @@ -64,6 +64,7 @@ class PodcastEpisode { int? duration; int? episode; String? image; + String? feedImage; String? guid; String? chaptersUrl; bool isAudio; @@ -79,6 +80,7 @@ class PodcastEpisode { this.duration, this.episode, this.image, + this.feedImage, this.guid, this.chaptersUrl, required this.isAudio}); @@ -88,6 +90,16 @@ class PodcastEpisode { String toRawJson() => json.encode(toJson()); + String? get networkImage { + if (image != null && image!.isNotEmpty) { + return image; + } + if (feedImage != null && feedImage!.isNotEmpty) { + return feedImage; + } + return null; + } + factory PodcastEpisode.fromJson(Map json) => PodcastEpisode( id: json["id"].toString(), isAudio: @@ -101,6 +113,7 @@ class PodcastEpisode { duration: json["duration"], episode: json["episode"], image: json["image"], + feedImage : json["feedImage"], guid: json["guid"], chaptersUrl: json['chaptersUrl']); diff --git a/lib/src/models/podcast/trending_podcast_response.dart b/lib/src/models/podcast/trending_podcast_response.dart index cb1b626a..59728869 100644 --- a/lib/src/models/podcast/trending_podcast_response.dart +++ b/lib/src/models/podcast/trending_podcast_response.dart @@ -67,6 +67,9 @@ class PodCastFeedItem { if (feedImage != null && feedImage!.isNotEmpty) { return feedImage; } + if (artwork != null && artwork!.isNotEmpty) { + return artwork; + } return null; } diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart index 7b68097f..2a7d5795 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart @@ -27,18 +27,20 @@ class _BottomNavBarState extends State { @override Widget build(BuildContext context) { final theme = Theme.of(context); - return SizedBox( - height: 65, - child: BottomNavigationBar( - showUnselectedLabels: true, - selectedFontSize: 11, - unselectedFontSize: 11, - type: BottomNavigationBarType.fixed, - items: navItems, - onTap: (index) => navigate(index, context), - selectedItemColor: theme.primaryColorLight, - unselectedItemColor: theme.primaryColorLight, - backgroundColor: theme.primaryColorDark, + return SafeArea( + child: SizedBox( + height: 65, + child: BottomNavigationBar( + showUnselectedLabels: true, + selectedFontSize: 11, + unselectedFontSize: 11, + type: BottomNavigationBarType.fixed, + items: navItems, + onTap: (index) => navigate(index, context), + selectedItemColor: theme.primaryColorLight, + unselectedItemColor: theme.primaryColorLight, + backgroundColor: theme.primaryColorDark, + ), ), ); } diff --git a/lib/src/screens/podcast/controller/podcast_player_controller.dart b/lib/src/screens/podcast/controller/podcast_player_controller.dart index 333823eb..5ef33b94 100644 --- a/lib/src/screens/podcast/controller/podcast_player_controller.dart +++ b/lib/src/screens/podcast/controller/podcast_player_controller.dart @@ -64,7 +64,7 @@ class PodcastPlayerController extends ChangeNotifier { _initiatePlay(context, episodes, index, playOnMiniPlayer); } - void onDefaultPlay(BuildContext context, bool playOnMiniPlayer) async { + void onDefaultPlay(BuildContext context,List episodes, bool playOnMiniPlayer) async { await _addEpisodesToQueue(episodes); _initiatePlay(context, episodes, 0, playOnMiniPlayer); } diff --git a/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart b/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart index d900b1ad..56634f9d 100644 --- a/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart +++ b/lib/src/screens/podcast/view/podcast_episodes/podcast_episodes_view.dart @@ -143,7 +143,7 @@ class _PodcastEpisodesViewState extends State { padding: const EdgeInsets.symmetric(vertical: 15), child: FilledButton.icon( onPressed: () => playerController.onDefaultPlay( - context, widget.playOnMiniPlayer), + context,episodes, widget.playOnMiniPlayer), style: FilledButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: @@ -182,7 +182,7 @@ class _PodcastEpisodesViewState extends State { : Icon(Icons.play_circle_outline_outlined); }), leading: CachedImage( - imageUrl: item.image, + imageUrl: item.networkImage, imageHeight: 48, imageWidth: 48, loadingIndicatorSize: 25, diff --git a/lib/src/screens/podcast/view/podcast_trending.dart b/lib/src/screens/podcast/view/podcast_trending.dart index 76a8749d..bc2e65d4 100644 --- a/lib/src/screens/podcast/view/podcast_trending.dart +++ b/lib/src/screens/podcast/view/podcast_trending.dart @@ -98,8 +98,13 @@ class _PodCastTrendingScreenState extends State onWillPop: () async { final NavigatorState navigatorState = miniPlayerNavigatorkey.currentState!; - if (!navigatorState.canPop()) return true; + + if (!navigatorState.canPop()) { + Navigator.of(context).pop(); + return true; + } navigatorState.pop(); + return false; }, child: Stack( @@ -137,7 +142,8 @@ class _PodCastTrendingScreenState extends State IconButton( onPressed: () { var screen = PodCastSearch(appData: widget.appData); - var route = MaterialPageRoute(builder: (c) => screen); + var route = + MaterialPageRoute(builder: (c) => screen); Navigator.of(context).push(route); }, icon: Icon(Icons.search), @@ -152,7 +158,8 @@ class _PodCastTrendingScreenState extends State controller: _tabController, children: [ PodcastFeedsBody( - future: trendingFeeds, appData: widget.appData), + future: trendingFeeds, + appData: widget.appData), _rssPodcastTab(context), PodcastCategoriesBody( appData: widget.appData, @@ -180,25 +187,27 @@ class _PodCastTrendingScreenState extends State ), ), ), - Consumer( - builder: (context, value, child) { - return Miniplayer( - controller: value.miniplayerController, - minHeight: value.episodes.isEmpty ? 0 : 65, - maxHeight: MediaQuery.of(context).size.height, - builder: (height, percentage) { - if (value.episodes.isEmpty) { - return SizedBox.shrink(); - } else { - return NewPodcastEpidosePlayer( - key: ValueKey(value.episodes.first.id), - dragValue: percentage, - podcastEpisodes: value.episodes, - currentPodcastIndex: value.index); - } - }, - ); - }, + SafeArea( + child: Consumer( + builder: (context, value, child) { + return Miniplayer( + controller: value.miniplayerController, + minHeight: value.episodes.isEmpty ? 0 : 65, + maxHeight: MediaQuery.of(context).size.height, + builder: (height, percentage) { + if (value.episodes.isEmpty) { + return SizedBox.shrink(); + } else { + return NewPodcastEpidosePlayer( + key: ValueKey(value.episodes.first.id), + dragValue: percentage, + podcastEpisodes: value.episodes, + currentPodcastIndex: value.index); + } + }, + ); + }, + ), ) ], ), diff --git a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart index d232ff73..37c6c5b5 100644 --- a/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart +++ b/lib/src/screens/podcast/widgets/audio_player/new_pod_cast_epidose_player.dart @@ -82,7 +82,7 @@ class _NewPodcastEpidosePlayerState extends State { writeCurrentDurationLocal(); }); podcastController.isDurationContinuing = true; - originalImage = currentPodcastEpisode.image; + originalImage = currentPodcastEpisode.networkImage; originalTitle = currentPodcastEpisode.title!; // TO-DO: Ram to handle chapters for offline player // if (currentPodcastEpisode.enclosureUrl != null && currentPodcastEpisode.enclosureUrl!.startsWith("http")) { @@ -135,7 +135,7 @@ class _NewPodcastEpidosePlayerState extends State { audioPlayerHandler: _audioHandler); // } originalTitle = currentPodcastEpisode.title!; - originalImage = currentPodcastEpisode.image; + originalImage = currentPodcastEpisode.networkImage; }); } } @@ -154,195 +154,197 @@ class _NewPodcastEpidosePlayerState extends State { return ChangeNotifierProvider.value( value: chapterController, child: Scaffold( - body: Stack( - fit: StackFit.expand, - children: [ - if (originalImage != null && originalImage!.isNotEmpty) - CachedImage( - imageUrl: originalImage, - ), - if (originalImage != null && originalImage!.isNotEmpty) - Positioned.fill( - child: ClipRRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 40, sigmaY: 40), - child: const SizedBox.shrink(), + body: SafeArea( + child: Stack( + fit: StackFit.expand, + children: [ + if (originalImage != null && originalImage!.isNotEmpty) + CachedImage( + imageUrl: originalImage, + ), + if (originalImage != null && originalImage!.isNotEmpty) + Positioned.fill( + child: ClipRRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 40, sigmaY: 40), + child: const SizedBox.shrink(), + ), ), ), - ), - Positioned.fill( - child: Container( - decoration: BoxDecoration( - gradient: LinearGradient(colors: [ - theme.primaryColorDark, - theme.primaryColorDark.withOpacity(0.3) - ])), - )), - // if (widget.dragValue < 0.5) - Positioned( - top: 0, - left: 0, - right: 0, - child: Visibility( - maintainAnimation: true, - maintainSize: true, - maintainState: true, - visible: widget.dragValue < 0.5, - child: PodcastProgressBar( - duration: currentPodcastEpisode.duration, - positionStream: _positionDataStream), - )), - StreamBuilder( - stream: _audioHandler.mediaItem, - builder: (context, snapshot) { - return SingleChildScrollView( - physics: NeverScrollableScrollPhysics(), - child: SizedBox( - height: MediaQuery.of(context).size.height, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Spacer(), - _audioHandler.shouldPlayVideo() - ? SizedBox( - height: - MediaQuery.of(context).size.height * 0.45, - child: Center( - child: ValueListenableBuilder( - valueListenable: - _audioHandler.aspectRatioNotifier, - builder: (context, aspectRatio, child) { - return AspectRatio( - aspectRatio: aspectRatio ?? 1.5, - child: child); - }, - child: VideoPlayer( - _audioHandler.videoPlayerController!), - )), - ) - : Transform.translate( - offset: Offset( - lerpDouble(-150, 0, widget.dragValue) ?? 0, - lerpDouble(-152.5, 0, widget.dragValue) ?? 0, - ), - child: Container( - height: lerpDouble( - 50, - MediaQuery.of(context).size.height * + Positioned.fill( + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + theme.primaryColorDark, + theme.primaryColorDark.withOpacity(0.3) + ])), + )), + // if (widget.dragValue < 0.5) + Positioned( + top: 0, + left: 0, + right: 0, + child: Visibility( + maintainAnimation: true, + maintainSize: true, + maintainState: true, + visible: widget.dragValue < 0.5, + child: PodcastProgressBar( + duration: currentPodcastEpisode.duration, + positionStream: _positionDataStream), + )), + StreamBuilder( + stream: _audioHandler.mediaItem, + builder: (context, snapshot) { + return SingleChildScrollView( + physics: NeverScrollableScrollPhysics(), + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Spacer(), + _audioHandler.shouldPlayVideo() + ? SizedBox( + height: + MediaQuery.of(context).size.height * 0.45, + child: Center( + child: ValueListenableBuilder( + valueListenable: + _audioHandler.aspectRatioNotifier, + builder: (context, aspectRatio, child) { + return AspectRatio( + aspectRatio: aspectRatio ?? 1.5, + child: child); + }, + child: VideoPlayer( + _audioHandler.videoPlayerController!), + )), + ) + : Transform.translate( + offset: Offset( + lerpDouble(-150, 0, widget.dragValue) ?? 0, + lerpDouble(-152.5, 0, widget.dragValue) ?? 0, + ), + child: Container( + height: lerpDouble( + 50, + MediaQuery.of(context).size.height * + 0.45, + widget.dragValue) ?? + 0, + width: lerpDouble( + 50, + MediaQuery.of(context).size.width * + 0.85, + widget.dragValue) ?? + 0, + margin: + EdgeInsets.symmetric(horizontal: 30), + // constraints: BoxConstraints( + // maxHeight: MediaQuery.of(context) + // .size + // .height * + // 0.45), + child: Selector( + selector: (_, myType) => myType.image, + builder: (context, chapterImage, child) { + return CachedImage( + imageUrl: + chapterImage ?? originalImage, + imageHeight: MediaQuery.of(context) + .size + .height * 0.45, - widget.dragValue) ?? - 0, - width: lerpDouble( - 50, - MediaQuery.of(context).size.width * - 0.85, - widget.dragValue) ?? - 0, - margin: - EdgeInsets.symmetric(horizontal: 30), - // constraints: BoxConstraints( - // maxHeight: MediaQuery.of(context) - // .size - // .height * - // 0.45), - child: Selector( - selector: (_, myType) => myType.image, - builder: (context, chapterImage, child) { - return CachedImage( - imageUrl: - chapterImage ?? originalImage, - imageHeight: MediaQuery.of(context) - .size - .height * - 0.45, - ); - }, - )), - ), - Spacer(), - AnimatedOpacity( - opacity: widget.dragValue == 1 - ? 1 - : widget.dragValue.clamp(0, 0.5), - duration: Duration(milliseconds: 150), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10), - child: Column( - children: [ - _title(screenWidth * 0.85), - const SizedBox( - height: 5, - ), - Text( - currentPodcastEpisode.datePublishedPretty - .toString(), - style: TextStyle(fontSize: 12), - ), - ], + ); + }, + )), + ), + Spacer(), + AnimatedOpacity( + opacity: widget.dragValue == 1 + ? 1 + : widget.dragValue.clamp(0, 0.5), + duration: Duration(milliseconds: 150), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + vertical: 15.0, horizontal: 10), + child: Column( + children: [ + _title(screenWidth * 0.85), + const SizedBox( + height: 5, + ), + Text( + currentPodcastEpisode.datePublishedPretty + .toString(), + style: TextStyle(fontSize: 12), + ), + ], + ), ), - ), - userToolbar(theme), - _slider(), - Gap(10), - ControlButtons( - _audioHandler, - chapterController: chapterController, - podcastEpisode: currentPodcastEpisode, - showSkipPreviousButtom: - widget.podcastEpisodes.length > 1, - positionStream: - _positionDataStream.asBroadcastStream(), - ), - ], + userToolbar(theme), + _slider(), + Gap(10), + ControlButtons( + _audioHandler, + chapterController: chapterController, + podcastEpisode: currentPodcastEpisode, + showSkipPreviousButtom: + widget.podcastEpisodes.length > 1, + positionStream: + _positionDataStream.asBroadcastStream(), + ), + ], + ), ), - ), - Spacer(), - ], + Spacer(), + ], + ), ), - ), - ); - }, - ), - if (widget.dragValue < 0.5) - AnimatedPositioned( - top: lerpDouble(10, 0, widget.dragValue), - left: lerpDouble(80, 20, widget.dragValue), - right: 10, - duration: Duration(milliseconds: 100), - child: AnimatedOpacity( - opacity: (lerpDouble(1, 6, widget.dragValue * (-0.5)) ?? 0) - .clamp(0, 1), + ); + }, + ), + if (widget.dragValue < 0.5) + AnimatedPositioned( + top: lerpDouble(10, 0, widget.dragValue), + left: lerpDouble(80, 20, widget.dragValue), + right: 10, duration: Duration(milliseconds: 100), - child: Padding( - padding: const EdgeInsets.only(left: 0.0, right: 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Align( - alignment: Alignment.centerLeft, - child: _title(screenWidth * 0.75, - height: 15, fontSize: 14)), - ControlButtons( - _audioHandler, - smallSize: true, - chapterController: chapterController, - podcastEpisode: currentPodcastEpisode, - showSkipPreviousButtom: - widget.podcastEpisodes.length > 1, - positionStream: - _positionDataStream.asBroadcastStream(), - ), - ], + child: AnimatedOpacity( + opacity: (lerpDouble(1, 6, widget.dragValue * (-0.5)) ?? 0) + .clamp(0, 1), + duration: Duration(milliseconds: 100), + child: Padding( + padding: const EdgeInsets.only(left: 0.0, right: 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Align( + alignment: Alignment.centerLeft, + child: _title(screenWidth * 0.75, + height: 15, fontSize: 14)), + ControlButtons( + _audioHandler, + smallSize: true, + chapterController: chapterController, + podcastEpisode: currentPodcastEpisode, + showSkipPreviousButtom: + widget.podcastEpisodes.length > 1, + positionStream: + _positionDataStream.asBroadcastStream(), + ), + ], + ), ), ), ), - ), - ], + ], + ), ), ), ); From cc9c6881658ce3e53122d00237223d0b3f00178c Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 3 May 2024 18:57:42 +0530 Subject: [PATCH 409/466] bug fixed for iOS - GetAccountInfo --- ios/Podfile.lock | 198 +++++++++++++----------- ios/Runner/AcelaWebViewController.swift | 5 +- 2 files changed, 109 insertions(+), 94 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 050cfbd7..ac2a8a2a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -18,35 +18,35 @@ PODS: - Flutter - device_info_plus (0.0.1): - Flutter - - DKImagePickerController/Core (4.3.4): + - DKImagePickerController/Core (4.3.8): - DKImagePickerController/ImageDataManager - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.4) - - DKImagePickerController/PhotoGallery (4.3.4): + - DKImagePickerController/ImageDataManager (4.3.8) + - DKImagePickerController/PhotoGallery (4.3.8): - DKImagePickerController/Core - DKPhotoGallery - - DKImagePickerController/Resource (4.3.4) - - DKPhotoGallery (0.0.17): - - DKPhotoGallery/Core (= 0.0.17) - - DKPhotoGallery/Model (= 0.0.17) - - DKPhotoGallery/Preview (= 0.0.17) - - DKPhotoGallery/Resource (= 0.0.17) + - DKImagePickerController/Resource (4.3.8) + - DKPhotoGallery (0.0.18): + - DKPhotoGallery/Core (= 0.0.18) + - DKPhotoGallery/Model (= 0.0.18) + - DKPhotoGallery/Preview (= 0.0.18) + - DKPhotoGallery/Resource (= 0.0.18) - SDWebImage - SwiftyGif - - DKPhotoGallery/Core (0.0.17): + - DKPhotoGallery/Core (0.0.18): - DKPhotoGallery/Model - DKPhotoGallery/Preview - SDWebImage - SwiftyGif - - DKPhotoGallery/Model (0.0.17): + - DKPhotoGallery/Model (0.0.18): - SDWebImage - SwiftyGif - - DKPhotoGallery/Preview (0.0.17): + - DKPhotoGallery/Preview (0.0.18): - DKPhotoGallery/Model - DKPhotoGallery/Resource - SDWebImage - SwiftyGif - - DKPhotoGallery/Resource (0.0.17): + - DKPhotoGallery/Resource (0.0.18): - SDWebImage - SwiftyGif - ffmpeg-kit-ios-https (5.1) @@ -59,73 +59,76 @@ PODS: - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter - - Firebase/Analytics (10.20.0): + - Firebase/Analytics (10.24.0): - Firebase/Core - - Firebase/Core (10.20.0): + - Firebase/Core (10.24.0): - Firebase/CoreOnly - - FirebaseAnalytics (~> 10.20.0) - - Firebase/CoreOnly (10.20.0): - - FirebaseCore (= 10.20.0) - - Firebase/Crashlytics (10.20.0): + - FirebaseAnalytics (~> 10.24.0) + - Firebase/CoreOnly (10.24.0): + - FirebaseCore (= 10.24.0) + - Firebase/Crashlytics (10.24.0): - Firebase/CoreOnly - - FirebaseCrashlytics (~> 10.20.0) - - firebase_analytics (10.8.5): - - Firebase/Analytics (= 10.20.0) + - FirebaseCrashlytics (~> 10.24.0) + - firebase_analytics (10.10.4): + - Firebase/Analytics (= 10.24.0) - firebase_core - Flutter - - firebase_core (2.25.4): - - Firebase/CoreOnly (= 10.20.0) + - firebase_core (2.30.1): + - Firebase/CoreOnly (= 10.24.0) - Flutter - - firebase_crashlytics (3.4.14): - - Firebase/Crashlytics (= 10.20.0) + - firebase_crashlytics (3.5.4): + - Firebase/Crashlytics (= 10.24.0) - firebase_core - Flutter - - FirebaseAnalytics (10.20.0): - - FirebaseAnalytics/AdIdSupport (= 10.20.0) + - FirebaseAnalytics (10.24.0): + - FirebaseAnalytics/AdIdSupport (= 10.24.0) - FirebaseCore (~> 10.0) - FirebaseInstallations (~> 10.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/Network (~> 7.11) - "GoogleUtilities/NSData+zlib (~> 7.11)" - - nanopb (< 2.30910.0, >= 2.30908.0) - - FirebaseAnalytics/AdIdSupport (10.20.0): + - nanopb (< 2.30911.0, >= 2.30908.0) + - FirebaseAnalytics/AdIdSupport (10.24.0): - FirebaseCore (~> 10.0) - FirebaseInstallations (~> 10.0) - - GoogleAppMeasurement (= 10.20.0) + - GoogleAppMeasurement (= 10.24.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/Network (~> 7.11) - "GoogleUtilities/NSData+zlib (~> 7.11)" - - nanopb (< 2.30910.0, >= 2.30908.0) - - FirebaseCore (10.20.0): + - nanopb (< 2.30911.0, >= 2.30908.0) + - FirebaseCore (10.24.0): - FirebaseCoreInternal (~> 10.0) - GoogleUtilities/Environment (~> 7.12) - GoogleUtilities/Logger (~> 7.12) - - FirebaseCoreExtension (10.21.0): + - FirebaseCoreExtension (10.25.0): - FirebaseCore (~> 10.0) - - FirebaseCoreInternal (10.21.0): + - FirebaseCoreInternal (10.25.0): - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseCrashlytics (10.20.0): + - FirebaseCrashlytics (10.24.0): - FirebaseCore (~> 10.5) - FirebaseInstallations (~> 10.0) + - FirebaseRemoteConfigInterop (~> 10.23) - FirebaseSessions (~> 10.5) - GoogleDataTransport (~> 9.2) - GoogleUtilities/Environment (~> 7.8) - - nanopb (< 2.30910.0, >= 2.30908.0) + - nanopb (< 2.30911.0, >= 2.30908.0) - PromisesObjC (~> 2.1) - - FirebaseInstallations (10.21.0): + - FirebaseInstallations (10.25.0): - FirebaseCore (~> 10.0) - GoogleUtilities/Environment (~> 7.8) - GoogleUtilities/UserDefaults (~> 7.8) - PromisesObjC (~> 2.1) - - FirebaseSessions (10.21.0): + - FirebaseRemoteConfigInterop (10.25.0) + - FirebaseSessions (10.25.0): - FirebaseCore (~> 10.5) - FirebaseCoreExtension (~> 10.0) - FirebaseInstallations (~> 10.0) - GoogleDataTransport (~> 9.2) - - GoogleUtilities/Environment (~> 7.10) - - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleUtilities/Environment (~> 7.13) + - GoogleUtilities/UserDefaults (~> 7.13) + - nanopb (< 2.30911.0, >= 2.30908.0) - PromisesSwift (~> 2.1) - Flutter (1.0.0) - flutter_downloader (0.0.1): @@ -136,49 +139,58 @@ PODS: - GCDWebServer (3.5.4): - GCDWebServer/Core (= 3.5.4) - GCDWebServer/Core (3.5.4) - - GoogleAppMeasurement (10.20.0): - - GoogleAppMeasurement/AdIdSupport (= 10.20.0) + - GoogleAppMeasurement (10.24.0): + - GoogleAppMeasurement/AdIdSupport (= 10.24.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/Network (~> 7.11) - "GoogleUtilities/NSData+zlib (~> 7.11)" - - nanopb (< 2.30910.0, >= 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (10.20.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 10.20.0) + - nanopb (< 2.30911.0, >= 2.30908.0) + - GoogleAppMeasurement/AdIdSupport (10.24.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 10.24.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/Network (~> 7.11) - "GoogleUtilities/NSData+zlib (~> 7.11)" - - nanopb (< 2.30910.0, >= 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (10.20.0): + - nanopb (< 2.30911.0, >= 2.30908.0) + - GoogleAppMeasurement/WithoutAdIdSupport (10.24.0): - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/Network (~> 7.11) - "GoogleUtilities/NSData+zlib (~> 7.11)" - - nanopb (< 2.30910.0, >= 2.30908.0) - - GoogleDataTransport (9.3.0): + - nanopb (< 2.30911.0, >= 2.30908.0) + - GoogleDataTransport (9.4.1): - GoogleUtilities/Environment (~> 7.7) - - nanopb (< 2.30910.0, >= 2.30908.0) + - nanopb (< 2.30911.0, >= 2.30908.0) - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/AppDelegateSwizzler (7.12.0): + - GoogleUtilities/AppDelegateSwizzler (7.13.2): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - - GoogleUtilities/Environment (7.12.0): + - GoogleUtilities/Privacy + - GoogleUtilities/Environment (7.13.2): + - GoogleUtilities/Privacy - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.12.0): + - GoogleUtilities/Logger (7.13.2): - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (7.12.0): + - GoogleUtilities/Privacy + - GoogleUtilities/MethodSwizzler (7.13.2): - GoogleUtilities/Logger - - GoogleUtilities/Network (7.12.0): + - GoogleUtilities/Privacy + - GoogleUtilities/Network (7.13.2): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Privacy - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.12.0)" - - GoogleUtilities/Reachability (7.12.0): + - "GoogleUtilities/NSData+zlib (7.13.2)": + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (7.13.2) + - GoogleUtilities/Reachability (7.13.2): - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (7.12.0): + - GoogleUtilities/Privacy + - GoogleUtilities/UserDefaults (7.13.2): - GoogleUtilities/Logger + - GoogleUtilities/Privacy - HLSCachingReverseProxyServer (0.1.0): - GCDWebServer (~> 3.5) - PINCache (>= 3.0.1-beta.3) @@ -201,11 +213,11 @@ PODS: - libwebp/sharpyuv (1.3.2) - libwebp/webp (1.3.2): - libwebp/sharpyuv - - nanopb (2.30909.1): - - nanopb/decode (= 2.30909.1) - - nanopb/encode (= 2.30909.1) - - nanopb/decode (2.30909.1) - - nanopb/encode (2.30909.1) + - nanopb (2.30910.0): + - nanopb/decode (= 2.30910.0) + - nanopb/encode (= 2.30910.0) + - nanopb/decode (2.30910.0) + - nanopb/encode (2.30910.0) - package_info_plus (0.4.5): - Flutter - path_provider_foundation (0.0.1): @@ -221,12 +233,12 @@ PODS: - PINCache/Core (3.0.3): - PINOperation (~> 1.2.1) - PINOperation (1.2.2) - - PromisesObjC (2.3.1) - - PromisesSwift (2.3.1): - - PromisesObjC (= 2.3.1) - - SDWebImage (5.18.10): - - SDWebImage/Core (= 5.18.10) - - SDWebImage/Core (5.18.10) + - PromisesObjC (2.4.0) + - PromisesSwift (2.4.0): + - PromisesObjC (= 2.4.0) + - SDWebImage (5.19.1): + - SDWebImage/Core (= 5.19.1) + - SDWebImage/Core (5.19.1) - Sentry/HybridSDK (8.19.0): - SentryPrivate (= 8.19.0) - sentry_flutter (0.0.1): @@ -242,7 +254,7 @@ PODS: - sqflite (0.0.3): - Flutter - FlutterMacOS - - SwiftyGif (5.4.4) + - SwiftyGif (5.4.5) - url_launcher_ios (0.0.1): - Flutter - video_compress (0.3.0): @@ -308,6 +320,7 @@ SPEC REPOS: - FirebaseCoreInternal - FirebaseCrashlytics - FirebaseInstallations + - FirebaseRemoteConfigInterop - FirebaseSessions - FYVideoCompressor - GCDWebServer @@ -400,51 +413,52 @@ SPEC CHECKSUMS: Cache: 4ca7e00363fca5455f26534e5607634c820ffc2d croppy: b6199bc8d56bd2e03cc11609d1c47ad9875c1321 device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed - DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac - DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 + DKImagePickerController: a7836546cfdfe014171694f643a7d575bc8ace7f + DKPhotoGallery: acbd8a3bab19cf6e5fe64a853fc07bfbd247a8f6 ffmpeg-kit-ios-https: 8dffbe1623a2f227be98fc314294847a97f818e4 ffmpeg_kit_flutter: 17e9f35a4ec996ac55051c20be05240f2a0b53e8 file_picker: ce3938a0df3cc1ef404671531facef740d03f920 - Firebase: 10c8cb12fb7ad2ae0c09ffc86cd9c1ab392a0031 - firebase_analytics: 2e82fd84ce13f8321aa7b99336d6ee0e6cc7b984 - firebase_core: a46c312d8bae4defa3d009b2aa7b5b413aeb394e - firebase_crashlytics: 3d12285fcbd865d576b9965bd4090cd8b68e11fd - FirebaseAnalytics: a2731bf3670747ce8f65368b118d18aa8e368246 - FirebaseCore: 28045c1560a2600d284b9c45a904fe322dc890b6 - FirebaseCoreExtension: 1c044fd46e95036cccb29134757c499613f3f564 - FirebaseCoreInternal: 43c1788eaeee9d1b97caaa751af567ce11010d00 - FirebaseCrashlytics: 81530595edb6d99f1918f723a6c33766a24a4c86 - FirebaseInstallations: 390ea1d10a4d02b20c965cbfd527ee9b3b412acb - FirebaseSessions: 80c2bbdd28166267b3d132debe5f7531efdb00bc + Firebase: 91fefd38712feb9186ea8996af6cbdef41473442 + firebase_analytics: 573fd0677abf22d32e2820865fc5190b6cdbfa1b + firebase_core: 7f1e1156934d0da3be260174812842df9420e4ab + firebase_crashlytics: 9815effbfaad6c94c65d4eff479c0d9284bf1a38 + FirebaseAnalytics: b5efc493eb0f40ec560b04a472e3e1a15d39ca13 + FirebaseCore: 11dc8a16dfb7c5e3c3f45ba0e191a33ac4f50894 + FirebaseCoreExtension: 8a47811d0b155501559ef05d089518152a0a1677 + FirebaseCoreInternal: 910a81992c33715fec9263ca7381d59ab3a750b7 + FirebaseCrashlytics: af38ea4adfa606f6e63fcc22091b61e7938fcf66 + FirebaseInstallations: 91950fe859846fff0fbd296180909dd273103b09 + FirebaseRemoteConfigInterop: b25018791b204c0d78a90e394d6c62d9b1f22da8 + FirebaseSessions: c0939656253a1fa0e94ecc266ccf770cc8b33732 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_downloader: b7301ae057deadd4b1650dc7c05375f10ff12c39 flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be FYVideoCompressor: 80e2a90bbc118044038b37b8442f23084c5698bf GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4 - GoogleAppMeasurement: bb3c564c3efb933136af0e94899e0a46167466a8 - GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe - GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34 + GoogleAppMeasurement: f3abf08495ef2cba7829f15318c373b8d9226491 + GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a + GoogleUtilities: c56430aef51a1aa57b25da78c3f8397e522c67b7 HLSCachingReverseProxyServer: 59935e1e0244ad7f3375d75b5ef46e8eb26ab181 image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425 images_picker: fa9364e3a7d3083c49f865fcfb2b9e7cdc574d3a just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 - nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5 + nanopb: 438bc412db1928dac798aa6fd75726007be04262 package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 PINOperation: daa34d4aa1d8449089be7d405b9d974abc4724c6 - PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 - PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265 - SDWebImage: fc8f2d48bbfd72ef39d70e981bd24a3f3be53fec + PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 + SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb Sentry: 1ebcaef678a27c8ac515f974cb5425dd1bbdec2f sentry_flutter: ecdfbedee55337205561cfa782ee02d31ec83e1f SentryPrivate: 765c9b4ebe9ac1a5fcdc067c5a1cfbf3f10e1677 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec - SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f + SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe video_player_avfoundation: 02011213dab73ae3687df27ce441fbbcc82b5579 diff --git a/ios/Runner/AcelaWebViewController.swift b/ios/Runner/AcelaWebViewController.swift index ed90d79e..fc1a8217 100644 --- a/ios/Runner/AcelaWebViewController.swift +++ b/ios/Runner/AcelaWebViewController.swift @@ -329,9 +329,10 @@ extension AcelaWebViewController: WKScriptMessageHandler { getDecryptedChallengeHandler?(response) case "getAccountInfo": guard - let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) + let data = try? JSONSerialization.data(withJSONObject: dict), + let string = String(data: data, encoding: .utf8) else { return } - getAccountInfoHandler?(response) + getAccountInfoHandler?(string) case "doWeHavePostingAuth": guard let response = ValidateHiveKeyResponse.jsonStringFrom(dict: dict) From 081292ccf3c0eb6190ff77a041f8e0a51651e7b1 Mon Sep 17 00:00:00 2001 From: Sagar Date: Fri, 3 May 2024 19:22:09 +0530 Subject: [PATCH 410/466] podcast back button pop fix attempt --- .../widgets/bottom_nav_bar.dart | 2 +- .../podcast/view/podcast_trending.dart | 219 +++++++++--------- 2 files changed, 115 insertions(+), 106 deletions(-) diff --git a/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart b/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart index 2a7d5795..f4bf78fe 100644 --- a/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart +++ b/lib/src/screens/home_screen/home_screen_feed_item/widgets/bottom_nav_bar.dart @@ -174,7 +174,7 @@ class _BottomNavBarState extends State { void _onTapPodcast() { var screen = PodCastTrendingScreen(appData: widget.appData); var route = MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); + Navigator.of(context,rootNavigator: true).push(route); } void _onTapSearch() { diff --git a/lib/src/screens/podcast/view/podcast_trending.dart b/lib/src/screens/podcast/view/podcast_trending.dart index bc2e65d4..ff480c6c 100644 --- a/lib/src/screens/podcast/view/podcast_trending.dart +++ b/lib/src/screens/podcast/view/podcast_trending.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:acela/src/models/podcast/podcast_categories_response.dart'; import 'package:acela/src/models/podcast/trending_podcast_response.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; @@ -94,122 +96,129 @@ class _PodCastTrendingScreenState extends State : currentIndex == 3 ? 'Recent Podcasts & Episodes' : 'Live Podcasts'; - return MiniplayerWillPopScope( - onWillPop: () async { - final NavigatorState navigatorState = - miniPlayerNavigatorkey.currentState!; - - if (!navigatorState.canPop()) { - Navigator.of(context).pop(); - return true; - } - navigatorState.pop(); - - return false; - }, - child: Stack( - children: [ - Navigator( - key: miniPlayerNavigatorkey, - onGenerateRoute: (settings) => MaterialPageRoute( - settings: settings, - builder: (context) => DefaultTabController( - length: 5, - child: Scaffold( - appBar: AppBar( - leadingWidth: 30, - title: ListTile( - contentPadding: EdgeInsets.zero, - leading: Image.asset( - 'assets/pod-cast-logo-round.png', - width: 40, - height: 40, - ), - title: Text('Podcasts'), - subtitle: Text(text), - ), - bottom: TabBar( - controller: _tabController, - tabs: [ - Tab(icon: const Icon(Icons.trending_up)), - Tab(icon: const Icon(FontAwesomeIcons.rss)), - Tab(icon: const Icon(Icons.category)), - Tab(icon: const Icon(Icons.music_note)), - Tab(icon: const Icon(Icons.live_tv)), - ], - ), - actions: [ - IconButton( + return PopScope( + canPop: true, + child: MiniplayerWillPopScope( + onWillPop: () async { + final NavigatorState navigatorState = + miniPlayerNavigatorkey.currentState!; + if (!navigatorState.canPop()) { + Navigator.of(context, rootNavigator: true).pop(); + return true; + } + navigatorState.pop(); + return false; + }, + child: Stack( + children: [ + Navigator( + key: miniPlayerNavigatorkey, + onGenerateRoute: (settings) => MaterialPageRoute( + settings: settings, + builder: (context) => DefaultTabController( + length: 5, + child: Scaffold( + appBar: AppBar( + leading: BackButton( onPressed: () { - var screen = PodCastSearch(appData: widget.appData); - var route = - MaterialPageRoute(builder: (c) => screen); - Navigator.of(context).push(route); + log('popp'); + Navigator.of(context, rootNavigator: true).pop(); }, - icon: Icon(Icons.search), ), - _postPodcastButton(widget.appData) - ], - ), - body: SafeArea( - child: Stack( - children: [ - TabBarView( - controller: _tabController, - children: [ - PodcastFeedsBody( - future: trendingFeeds, - appData: widget.appData), - _rssPodcastTab(context), - PodcastCategoriesBody( - appData: widget.appData, - future: categories, - ), - PodcastFeedsBody( - future: recentFeeds, appData: widget.appData), - PodcastFeedsBody( - future: liveFeeds, appData: widget.appData), - ], + leadingWidth: 30, + title: ListTile( + contentPadding: EdgeInsets.zero, + leading: Image.asset( + 'assets/pod-cast-logo-round.png', + width: 40, + height: 40, ), - Consumer( - builder: (context, value, child) { - return Padding( - padding: EdgeInsets.only( - bottom: value.episodes.isEmpty ? 0 : 65.0), - child: _fabContainer(), - ); + title: Text('Podcasts'), + subtitle: Text(text), + ), + bottom: TabBar( + controller: _tabController, + tabs: [ + Tab(icon: const Icon(Icons.trending_up)), + Tab(icon: const Icon(FontAwesomeIcons.rss)), + Tab(icon: const Icon(Icons.category)), + Tab(icon: const Icon(Icons.music_note)), + Tab(icon: const Icon(Icons.live_tv)), + ], + ), + actions: [ + IconButton( + onPressed: () { + var screen = PodCastSearch(appData: widget.appData); + var route = + MaterialPageRoute(builder: (c) => screen); + Navigator.of(context).push(route); }, - ) + icon: Icon(Icons.search), + ), + _postPodcastButton(widget.appData) ], ), + body: SafeArea( + child: Stack( + children: [ + TabBarView( + controller: _tabController, + children: [ + PodcastFeedsBody( + future: trendingFeeds, + appData: widget.appData), + _rssPodcastTab(context), + PodcastCategoriesBody( + appData: widget.appData, + future: categories, + ), + PodcastFeedsBody( + future: recentFeeds, appData: widget.appData), + PodcastFeedsBody( + future: liveFeeds, appData: widget.appData), + ], + ), + Consumer( + builder: (context, value, child) { + return Padding( + padding: EdgeInsets.only( + bottom: value.episodes.isEmpty ? 0 : 65.0), + child: _fabContainer(), + ); + }, + ) + ], + ), + ), ), ), ), ), - ), - SafeArea( - child: Consumer( - builder: (context, value, child) { - return Miniplayer( - controller: value.miniplayerController, - minHeight: value.episodes.isEmpty ? 0 : 65, - maxHeight: MediaQuery.of(context).size.height, - builder: (height, percentage) { - if (value.episodes.isEmpty) { - return SizedBox.shrink(); - } else { - return NewPodcastEpidosePlayer( - key: ValueKey(value.episodes.first.id), - dragValue: percentage, - podcastEpisodes: value.episodes, - currentPodcastIndex: value.index); - } - }, - ); - }, - ), - ) - ], + SafeArea( + child: Consumer( + builder: (context, value, child) { + return Miniplayer( + controller: value.miniplayerController, + minHeight: value.episodes.isEmpty ? 0 : 65, + maxHeight: MediaQuery.of(context).size.height, + builder: (height, percentage) { + if (value.episodes.isEmpty) { + return SizedBox.shrink(); + } else { + return NewPodcastEpidosePlayer( + key: ValueKey(value.episodes.first.id), + dragValue: percentage, + podcastEpisodes: value.episodes, + currentPodcastIndex: value.index); + } + }, + ); + }, + ), + ) + ], + ), ), ); } From 5e6727c6be11dbbc390efb9e01a3deaeaa712ce5 Mon Sep 17 00:00:00 2001 From: Sagar Date: Fri, 3 May 2024 20:55:55 +0530 Subject: [PATCH 411/466] flashy test on finishing video upload --- .../upload/video/video_upload_screen.dart | 39 ++---- .../widgets/video_upload_success_dialog.dart | 125 ++++++++++++++++++ 2 files changed, 136 insertions(+), 28 deletions(-) create mode 100644 lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart diff --git a/lib/src/screens/upload/video/video_upload_screen.dart b/lib/src/screens/upload/video/video_upload_screen.dart index 5b6d44a5..3d3336df 100644 --- a/lib/src/screens/upload/video/video_upload_screen.dart +++ b/lib/src/screens/upload/video/video_upload_screen.dart @@ -1,9 +1,7 @@ import 'dart:io'; - import 'package:acela/src/models/user_account/action_response.dart'; import 'package:acela/src/models/user_account/user_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; -import 'package:acela/src/screens/my_account/my_account_screen.dart'; import 'package:acela/src/screens/upload/video/controller/video_upload_controller.dart'; import 'package:acela/src/screens/upload/video/widgets/beneficaries_tile.dart'; import 'package:acela/src/screens/upload/video/widgets/community_picker.dart'; @@ -13,6 +11,7 @@ import 'package:acela/src/screens/upload/video/widgets/thumbnail_picker.dart'; import 'package:acela/src/screens/upload/video/widgets/uploadProgressExpansionTile.dart'; import 'package:acela/src/screens/upload/video/widgets/upload_textfield.dart'; import 'package:acela/src/screens/upload/video/widgets/video_upload_divider.dart'; +import 'package:acela/src/screens/upload/video/widgets/video_upload_success_dialog.dart'; import 'package:acela/src/screens/upload/video/widgets/work_type_widget.dart'; import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/enum.dart'; @@ -271,32 +270,16 @@ class _VideoUploadScreenState extends State { } void showSuccessDialog({required VoidCallback resetControllerCallback}) { - Widget okButton = TextButton( - child: Text("Okay"), - onPressed: () { - Navigator.of(context).pop(); - Navigator.of(context).pop(); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => MyAccountScreen( - data: widget.appData, - initialTabIndex: 2, - ), - ), - ); - }, - ); - AlertDialog alert = AlertDialog( - title: Text("🎉 Upload Complete 🎉"), - content: Text( - "✅ Your Video is in-process\n\n✅ Video has be added to encoding queue\n\n👀 Check status from My Account."), - actions: [ - okButton, - ], - ); - showDialog(context: context, builder: (c) => alert) - .whenComplete(() => resetControllerCallback()); + showDialog( + barrierDismissible: false, + context: context, + builder: (c) => VideoUploadSucessDialog( + + + )).whenComplete(() { + resetControllerCallback(); + Navigator.pop(context); + }); } Widget saveButton(VideoUploadController controller) { diff --git a/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart b/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart new file mode 100644 index 00000000..61108316 --- /dev/null +++ b/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart @@ -0,0 +1,125 @@ +import 'dart:async'; +import 'dart:math'; + +import 'package:flutter/material.dart'; + +class VideoUploadSucessDialog extends StatefulWidget { + const VideoUploadSucessDialog({ + Key? key, + }) : super(key: key); + + @override + State createState() => + _VideoUploadSucessDialogState(); +} + +class _VideoUploadSucessDialogState extends State { + late Timer colorChangeTimer; + late Timer enableButtonTimer; + int colorIndex = 0; + Random random = Random(); + bool enableButton = false; + + List colors = [ + Colors.red, + Colors.tealAccent, + Colors.blue, + Colors.pink, + Colors.purple, + Colors.yellow, + Colors.brown, + Colors.lightGreenAccent, + Colors.lime, + Colors.cyan, + Colors.amber, + Colors.redAccent + ]; + + @override + void initState() { + super.initState(); + + _init(); + } + + void _init() async { + colorChangeTimer = Timer.periodic(Duration(milliseconds: 500), (timer) { + if (mounted) { + setState(() { + colorIndex = random.nextInt(5); + }); + } + }); + enableButtonTimer = Timer.periodic(Duration(seconds: 5), (timer) { + if (mounted) { + setState(() { + enableButton = true; + enableButtonTimer.cancel(); + }); + } + }); + } + + @override + void dispose() { + colorChangeTimer.cancel(); + enableButtonTimer.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + if (enableButton) return true; + return false; + }, + child: AlertDialog( + title: Text("🎉 Upload Complete 🎉"), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "✅ Your Video is in-process.\n✅ Video has be added to encoding queue.\n⏳Video will be processed."), + SizedBox( + height: 10, + ), + Text( + "🚨 Your Video will be automatically published 🚨", + style: TextStyle( + color: colors[colorIndex], + fontSize: 15, + fontWeight: FontWeight.w700), + ) + ], + ), + actions: [ + Stack( + children: [ + TextButton( + style: TextButton.styleFrom( + backgroundColor: Theme.of(context).primaryColor), + child: Text("AutoPublish"), + onPressed: () { + Navigator.pop(context); + }, + ), + Positioned.fill( + top: 4, + bottom: 4, + child: Visibility( + visible: !enableButton, + child: Container( + decoration: BoxDecoration( + color: Colors.black12.withOpacity(0.5), + borderRadius: BorderRadius.all(Radius.circular(40))), + ), + ), + ), + ], + ), + ], + ), + ); + } +} From 66ae4c4d26354baa485e79bf65e5b5b49b3aa07c Mon Sep 17 00:00:00 2001 From: Sagar Date: Fri, 3 May 2024 21:01:13 +0530 Subject: [PATCH 412/466] timer value in success dialog --- .../widgets/video_upload_success_dialog.dart | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart b/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart index 61108316..74897d63 100644 --- a/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart +++ b/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart @@ -16,7 +16,9 @@ class VideoUploadSucessDialog extends StatefulWidget { class _VideoUploadSucessDialogState extends State { late Timer colorChangeTimer; late Timer enableButtonTimer; + late Timer valueTimer; int colorIndex = 0; + int timerCount = 5; Random random = Random(); bool enableButton = false; @@ -58,12 +60,23 @@ class _VideoUploadSucessDialogState extends State { }); } }); + valueTimer = Timer.periodic(Duration(seconds: 1), (timer) { + if (mounted) { + setState(() { + timerCount--; + if (timerCount == 0) { + valueTimer.cancel(); + } + }); + } + }); } @override void dispose() { colorChangeTimer.cancel(); enableButtonTimer.cancel(); + valueTimer.cancel(); super.dispose(); } @@ -99,7 +112,7 @@ class _VideoUploadSucessDialogState extends State { TextButton( style: TextButton.styleFrom( backgroundColor: Theme.of(context).primaryColor), - child: Text("AutoPublish"), + child: Text("AutoPublish ${timerCount!=0 ? timerCount : ""}"), onPressed: () { Navigator.pop(context); }, From eeeb539c916547b65bceeecc2f14ab1a251a07ac Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 3 May 2024 21:06:15 +0530 Subject: [PATCH 413/466] added line separator --- .idea/libraries/Flutter_Plugins.xml | 14 +++++++------- .../upload/video/mixins/video_save_mixin.dart | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 90c6ae68..00f2b311 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -49,12 +49,10 @@ - - @@ -62,12 +60,14 @@ - - - - - + + + + + + + diff --git a/lib/src/screens/upload/video/mixins/video_save_mixin.dart b/lib/src/screens/upload/video/mixins/video_save_mixin.dart index 648d05e5..b517c67f 100644 --- a/lib/src/screens/upload/video/mixins/video_save_mixin.dart +++ b/lib/src/screens/upload/video/mixins/video_save_mixin.dart @@ -30,7 +30,7 @@ class VideoSaveMixin { user: user, videoId: item.id, title: title, - description: "${description} Uploaded using 3Speak Mobile App", + description: "${description}\n\nUploaded using 3Speak Mobile App", isNsfwContent: isNsfwContent, tags: tags, thumbnail: thumbIpfs.isEmpty ? null : thumbIpfs, From 2f297a54254f33228bd662bb0a1d7ce35d654abd Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Fri, 3 May 2024 21:17:58 +0530 Subject: [PATCH 414/466] version bump --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 74021f30..85cb2afa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.5.4+97 +version: 3.0.0+98 environment: sdk: ">=2.15.1 <3.0.0" From 4002b4cad2dcf11728472edd3a5974ce59fce42e Mon Sep 17 00:00:00 2001 From: Sagar Date: Mon, 6 May 2024 12:29:45 +0530 Subject: [PATCH 415/466] posting authority is optional now --- .../controller/video_upload_controller.dart | 47 +++++++++---- .../upload/video/mixins/video_save_mixin.dart | 6 +- .../upload/video/video_upload_screen.dart | 67 +++++++++---------- .../widgets/video_upload_success_dialog.dart | 10 ++- 4 files changed, 78 insertions(+), 52 deletions(-) diff --git a/lib/src/screens/upload/video/controller/video_upload_controller.dart b/lib/src/screens/upload/video/controller/video_upload_controller.dart index ab65bfbe..c69f90ca 100644 --- a/lib/src/screens/upload/video/controller/video_upload_controller.dart +++ b/lib/src/screens/upload/video/controller/video_upload_controller.dart @@ -1,8 +1,11 @@ import 'package:acela/src/models/my_account/video_ops.dart'; +import 'package:acela/src/models/user_account/action_response.dart'; +import 'package:acela/src/models/user_account/user_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; import 'package:acela/src/screens/settings/settings_screen.dart'; import 'package:acela/src/screens/upload/video/mixins/video_save_mixin.dart'; import 'package:acela/src/screens/upload/video/mixins/video_upload_mixin.dart'; +import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/enum.dart'; import 'package:flutter/material.dart'; @@ -46,6 +49,9 @@ class VideoUploadController extends ChangeNotifier with Upload, VideoSaveMixin { void setBeneficiares({String? userName, bool resetBeneficiares = false}) { this.userName = userName ?? this.userName; if (beneficaries.isEmpty || resetBeneficiares) { + if (resetBeneficiares) { + beneficaries.clear(); + } if (this.userName != 'sagarkothari88') { beneficaries.add( BeneficiariesJson( @@ -81,7 +87,7 @@ class VideoUploadController extends ChangeNotifier with Upload, VideoSaveMixin { Future validateAndSaveVideo( HiveUserData userData, { - required VoidCallback successDialog, + required Function(bool) successDialog, required Function(String) successSnackbar, required Function(String) errorSnackbar, }) async { @@ -94,18 +100,33 @@ class VideoUploadController extends ChangeNotifier with Upload, VideoSaveMixin { } else if (thumbnailUploadResponse.value == null) { errorSnackbar('Thumbnail is Required'); } else { - await saveVideo(userData, uploadedVideoItem, - title: title, - description: description, - tags: tags, - beneficiaries: beneficaries, - communityId: communityId, - isNsfwContent: isNsfwContent, - language: language, - isPowerUp100: isPower100, - thumbIpfs: thumbnailUploadResponse.value!.name, - successDialog: successDialog, - errorSnackbar: errorSnackbar); + bool? hasPostingAuthoriy = await _hasPostingAuthority(); + if (hasPostingAuthoriy == null) { + errorSnackbar("Something went wrong, try again"); + } else { + await saveVideo(userData, uploadedVideoItem, hasPostingAuthoriy, + title: title, + description: description, + tags: tags, + beneficiaries: beneficaries, + communityId: communityId, + isNsfwContent: isNsfwContent, + language: language, + isPowerUp100: isPower100, + thumbIpfs: thumbnailUploadResponse.value!.name, + successDialog: () => successDialog(hasPostingAuthoriy), + errorSnackbar: errorSnackbar); + } + } + } + + Future _hasPostingAuthority() async { + ActionSingleDataResponse response = + await Communicator().getAccountInfo(this.userName); + if (response.isSuccess) { + return response.data!.hasThreeSpeakPostingAuthority(); + } else { + return null; } } diff --git a/lib/src/screens/upload/video/mixins/video_save_mixin.dart b/lib/src/screens/upload/video/mixins/video_save_mixin.dart index 648d05e5..0dbb2ac4 100644 --- a/lib/src/screens/upload/video/mixins/video_save_mixin.dart +++ b/lib/src/screens/upload/video/mixins/video_save_mixin.dart @@ -11,7 +11,8 @@ class VideoSaveMixin { Future saveVideo( HiveUserData user, - VideoUploadInfo item, { + VideoUploadInfo item, + bool hasPostingAuthority,{ required String title, required String description, required bool isNsfwContent, @@ -25,12 +26,13 @@ class VideoSaveMixin { required Function(String) errorSnackbar, }) async { try { + String body = "${description}${hasPostingAuthority ? " Uploaded using 3Speak Mobile App" : ""}"; isSaving.value = true; await Communicator().updateInfo( user: user, videoId: item.id, title: title, - description: "${description} Uploaded using 3Speak Mobile App", + description: body, isNsfwContent: isNsfwContent, tags: tags, thumbnail: thumbIpfs.isEmpty ? null : thumbIpfs, diff --git a/lib/src/screens/upload/video/video_upload_screen.dart b/lib/src/screens/upload/video/video_upload_screen.dart index 3d3336df..b68a54d2 100644 --- a/lib/src/screens/upload/video/video_upload_screen.dart +++ b/lib/src/screens/upload/video/video_upload_screen.dart @@ -1,7 +1,6 @@ import 'dart:io'; -import 'package:acela/src/models/user_account/action_response.dart'; -import 'package:acela/src/models/user_account/user_model.dart'; import 'package:acela/src/models/user_stream/hive_user_stream.dart'; +import 'package:acela/src/screens/my_account/my_account_screen.dart'; import 'package:acela/src/screens/upload/video/controller/video_upload_controller.dart'; import 'package:acela/src/screens/upload/video/widgets/beneficaries_tile.dart'; import 'package:acela/src/screens/upload/video/widgets/community_picker.dart'; @@ -13,7 +12,6 @@ import 'package:acela/src/screens/upload/video/widgets/upload_textfield.dart'; import 'package:acela/src/screens/upload/video/widgets/video_upload_divider.dart'; import 'package:acela/src/screens/upload/video/widgets/video_upload_success_dialog.dart'; import 'package:acela/src/screens/upload/video/widgets/work_type_widget.dart'; -import 'package:acela/src/utils/communicator.dart'; import 'package:acela/src/utils/enum.dart'; import 'package:acela/src/widgets/loading_screen.dart'; import 'package:flutter/material.dart'; @@ -216,38 +214,25 @@ class _VideoUploadScreenState extends State { controller.jumpToPage(); if (controller.uploadStatus.value == UploadStatus.idle) { try { - ActionSingleDataResponse response = - await Communicator().getAccountInfo(widget.appData.username!); - if (response.isSuccess) { - if (response.data!.hasThreeSpeakPostingAuthority()) { - final XFile? file; - // file = null; - file = await ImagePicker().pickVideo( - source: - widget.isCamera ? ImageSource.camera : ImageSource.gallery, - preferredCameraDevice: CameraDevice.front, - ); + final XFile? file; + // file = null; + file = await ImagePicker().pickVideo( + source: widget.isCamera ? ImageSource.camera : ImageSource.gallery, + preferredCameraDevice: CameraDevice.front, + ); - if (file != null) { - var fileToSave = File(file.path); - if (widget.isCamera) { - ImagesPicker.saveVideoToAlbum(fileToSave); - } - controller.onUpload( - hiveUserData: widget.appData, - pickedVideoFile: file, - ); - } else { - showMessage('Video Picker Cancelled'); - Navigator.pop(context); - } - } else { - Navigator.pop(context); - showMessage("Three speak posting authority is required to upload video"); + if (file != null) { + var fileToSave = File(file.path); + if (widget.isCamera) { + ImagesPicker.saveVideoToAlbum(fileToSave); } + controller.onUpload( + hiveUserData: widget.appData, + pickedVideoFile: file, + ); } else { + showMessage('Video Picker Cancelled'); Navigator.pop(context); - showMessage("Server error,please try again"); } } catch (e) { showMessage(e.toString()); @@ -269,16 +254,27 @@ class _VideoUploadScreenState extends State { ScaffoldMessenger.of(context).showSnackBar(snackBar); } - void showSuccessDialog({required VoidCallback resetControllerCallback}) { + void showSuccessDialog(bool hasPostingAuthority, + {required VoidCallback resetControllerCallback}) { showDialog( barrierDismissible: false, context: context, builder: (c) => VideoUploadSucessDialog( - - + hasPostingAuthority: hasPostingAuthority, )).whenComplete(() { resetControllerCallback(); Navigator.pop(context); + if (!hasPostingAuthority) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MyAccountScreen( + data: widget.appData, + initialTabIndex: 2, + ), + ), + ); + } }); } @@ -291,7 +287,8 @@ class _VideoUploadScreenState extends State { child: FloatingActionButton.extended( onPressed: () { controller.validateAndSaveVideo(widget.appData, - successDialog: () => showSuccessDialog( + successDialog: (hasPostingAuthority) => showSuccessDialog( + hasPostingAuthority, resetControllerCallback: controller.resetController), successSnackbar: (message) => showMessage( message, diff --git a/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart b/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart index 74897d63..e6ae3344 100644 --- a/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart +++ b/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart @@ -6,8 +6,11 @@ import 'package:flutter/material.dart'; class VideoUploadSucessDialog extends StatefulWidget { const VideoUploadSucessDialog({ Key? key, + required this.hasPostingAuthority, }) : super(key: key); + final bool hasPostingAuthority; + @override State createState() => _VideoUploadSucessDialogState(); @@ -98,7 +101,9 @@ class _VideoUploadSucessDialogState extends State { height: 10, ), Text( - "🚨 Your Video will be automatically published 🚨", + widget.hasPostingAuthority + ? "🚨 Your Video will be automatically published 🚨" + : "You'll have to publish this uploaded video from my account after video is processed", style: TextStyle( color: colors[colorIndex], fontSize: 15, @@ -112,7 +117,8 @@ class _VideoUploadSucessDialogState extends State { TextButton( style: TextButton.styleFrom( backgroundColor: Theme.of(context).primaryColor), - child: Text("AutoPublish ${timerCount!=0 ? timerCount : ""}"), + child: Text( + "${widget.hasPostingAuthority ? "AutoPublish" : "Okay. I will"} ${timerCount != 0 ? timerCount : ""}"), onPressed: () { Navigator.pop(context); }, From dc8737d36fea26b826bad4f330ebcaaabdc22474 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 7 May 2024 05:44:39 +0530 Subject: [PATCH 416/466] updated text --- .../upload/video/widgets/video_upload_success_dialog.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart b/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart index e6ae3344..c610454e 100644 --- a/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart +++ b/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart @@ -103,7 +103,7 @@ class _VideoUploadSucessDialogState extends State { Text( widget.hasPostingAuthority ? "🚨 Your Video will be automatically published 🚨" - : "You'll have to publish this uploaded video from my account after video is processed", + : "🚨 You'll have to publish this uploaded video from my account after video is processed. It will NOT be published automatically. 🚨 ", style: TextStyle( color: colors[colorIndex], fontSize: 15, From 48cde34ffe937bf869ce109d5619f56f4b70d9c4 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Tue, 7 May 2024 05:49:25 +0530 Subject: [PATCH 417/466] updated message. version bump --- .../upload/video/widgets/video_upload_success_dialog.dart | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart b/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart index c610454e..fe6b0960 100644 --- a/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart +++ b/lib/src/screens/upload/video/widgets/video_upload_success_dialog.dart @@ -103,7 +103,7 @@ class _VideoUploadSucessDialogState extends State { Text( widget.hasPostingAuthority ? "🚨 Your Video will be automatically published 🚨" - : "🚨 You'll have to publish this uploaded video from my account after video is processed. It will NOT be published automatically. 🚨 ", + : "🚨 You will have to publish from my account after it is processed. It will NOT be published automatically. 🚨 ", style: TextStyle( color: colors[colorIndex], fontSize: 15, diff --git a/pubspec.yaml b/pubspec.yaml index 85cb2afa..bff227d8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 3.0.0+98 +version: 3.0.1+99 environment: sdk: ">=2.15.1 <3.0.0" From 4a39cc5efe74e7da8dff3db9a17110ee44a226e4 Mon Sep 17 00:00:00 2001 From: Sagar Date: Mon, 13 May 2024 12:55:35 +0530 Subject: [PATCH 418/466] video upload beneficiaries passed to the api now --- .../video_upload_complete_request.dart | 3 +++ .../update_video/video_details_info.dart | 1 - lib/src/utils/communicator.dart | 23 +++++++++++-------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/src/models/video_upload/video_upload_complete_request.dart b/lib/src/models/video_upload/video_upload_complete_request.dart index ea81ea37..20c94944 100644 --- a/lib/src/models/video_upload/video_upload_complete_request.dart +++ b/lib/src/models/video_upload/video_upload_complete_request.dart @@ -8,6 +8,7 @@ class VideoUploadCompleteRequest { final String tags; final String? thumbnail; final String communityID; + final String? beneficiaries; VideoUploadCompleteRequest({ required this.videoId, @@ -17,6 +18,7 @@ class VideoUploadCompleteRequest { required this.tags, required this.thumbnail, required this.communityID, + required this.beneficiaries }); Map toJson() { @@ -27,6 +29,7 @@ class VideoUploadCompleteRequest { 'isNsfwContent': isNsfwContent, 'tags': tags, 'communityID': communityID, + 'beneficiaries' : beneficiaries }; if (thumbnail != null && thumbnail!.isNotEmpty) { map['thumbnail'] = thumbnail!; diff --git a/lib/src/screens/my_account/update_video/video_details_info.dart b/lib/src/screens/my_account/update_video/video_details_info.dart index 0c1850ec..9b0408b9 100644 --- a/lib/src/screens/my_account/update_video/video_details_info.dart +++ b/lib/src/screens/my_account/update_video/video_details_info.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; - import 'package:acela/src/bloc/server.dart'; import 'package:acela/src/global_provider/ipfs_node_provider.dart'; import 'package:acela/src/models/login/login_bridge_response.dart'; diff --git a/lib/src/utils/communicator.dart b/lib/src/utils/communicator.dart index e34e6e69..8491e86c 100644 --- a/lib/src/utils/communicator.dart +++ b/lib/src/utils/communicator.dart @@ -372,20 +372,23 @@ class Communicator { } } - Future updateInfo({ - required HiveUserData user, - required String videoId, - required String title, - required String description, - required bool isNsfwContent, - required String tags, - required String? thumbnail, - required String communityID, - }) async { + Future updateInfo( + {required HiveUserData user, + required String videoId, + required String title, + required String description, + required bool isNsfwContent, + required String tags, + required String? thumbnail, + required String communityID, + List? beneficiaries}) async { var request = http.Request( 'POST', Uri.parse('${Communicator.tsServer}/mobile/api/update_info')); var cookie = await getValidCookie(user); request.body = VideoUploadCompleteRequest( + beneficiaries: beneficiaries != null + ? json.encode(beneficiaries.map((e) => e.toJson()).toList()) + : null, videoId: videoId, title: title, description: description, From 34e75b25c87cd98da3ec054e2dff1dd5670dda80 Mon Sep 17 00:00:00 2001 From: no-do-not-track-me Date: Wed, 15 May 2024 16:56:25 +0530 Subject: [PATCH 419/466] bug fixes but these bug fixes have bugs --- android/.idea/gradle.xml | 6 +++--- .../update_video/add_bene_sheet.dart | 4 +++- .../update_video/video_details_info.dart | 18 ++++++++++-------- .../upload/video/mixins/video_save_mixin.dart | 7 ++++--- pubspec.yaml | 2 +- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml index df21879f..112c41f5 100644 --- a/android/.idea/gradle.xml +++ b/android/.idea/gradle.xml @@ -17,9 +17,9 @@

TG=(9DyAe-vJWctQ$Mrb-&s&rD52`qT}_6KmJ}u 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