mirror of
https://github.com/nostrlabs-io/zap-stream-flutter.git
synced 2025-06-15 19:48:23 +00:00
feat: zaps / profiles
This commit is contained in:
@ -16,7 +16,9 @@ class HomePage extends StatelessWidget {
|
||||
children: [
|
||||
HeaderWidget(),
|
||||
RxFilter<Nip01Event>(
|
||||
filter: Filter(kinds: [30_311], limit: 10),
|
||||
filters: [
|
||||
Filter(kinds: [30_311], limit: 50),
|
||||
],
|
||||
builder: (ctx, state) {
|
||||
if (state == null) {
|
||||
return SizedBox.shrink();
|
||||
|
@ -4,10 +4,11 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:ndk/shared/nips/nip19/nip19.dart';
|
||||
import 'package:zap_stream_flutter/login.dart';
|
||||
import 'package:zap_stream_flutter/main.dart';
|
||||
import 'package:zap_stream_flutter/theme.dart';
|
||||
import 'package:zap_stream_flutter/widgets/button.dart';
|
||||
|
||||
class LoginPage extends StatefulWidget {
|
||||
const LoginPage({super.key});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _LoginPage();
|
||||
}
|
||||
@ -42,7 +43,7 @@ class _LoginPage extends State<LoginPage> {
|
||||
}
|
||||
},
|
||||
),
|
||||
BasicButton.text("Login with Key"),
|
||||
/*BasicButton.text("Login with Key"),
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(vertical: 20),
|
||||
height: 1,
|
||||
@ -50,7 +51,7 @@ class _LoginPage extends State<LoginPage> {
|
||||
border: Border(bottom: BorderSide(color: LAYER_1)),
|
||||
),
|
||||
),
|
||||
Text("Create Account"),
|
||||
Text("Create Account"),*/
|
||||
],
|
||||
),
|
||||
);
|
||||
|
104
lib/pages/profile.dart
Normal file
104
lib/pages/profile.dart
Normal file
@ -0,0 +1,104 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:ndk/ndk.dart';
|
||||
import 'package:ndk/shared/nips/nip19/nip19.dart';
|
||||
import 'package:zap_stream_flutter/imgproxy.dart';
|
||||
import 'package:zap_stream_flutter/main.dart';
|
||||
import 'package:zap_stream_flutter/rx_filter.dart';
|
||||
import 'package:zap_stream_flutter/theme.dart';
|
||||
import 'package:zap_stream_flutter/widgets/avatar.dart';
|
||||
import 'package:zap_stream_flutter/widgets/button.dart';
|
||||
import 'package:zap_stream_flutter/widgets/header.dart';
|
||||
import 'package:zap_stream_flutter/widgets/profile.dart';
|
||||
import 'package:zap_stream_flutter/widgets/stream_grid.dart';
|
||||
|
||||
class ProfilePage extends StatelessWidget {
|
||||
final String pubkey;
|
||||
|
||||
const ProfilePage({super.key, required this.pubkey});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hexPubkey = Nip19.decode(pubkey);
|
||||
return ProfileLoaderWidget(hexPubkey, (ctx, state) {
|
||||
final profile = state.data ?? Metadata(pubKey: hexPubkey);
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 16,
|
||||
children: [
|
||||
HeaderWidget(),
|
||||
if (profile.banner != null)
|
||||
SizedBox(
|
||||
height: 140,
|
||||
width: double.maxFinite,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: proxyImg(context, profile.banner!),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
AvatarWidget(profile: profile, size: 80),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ProfileNameWidget(
|
||||
profile: profile,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
profile.about ?? "",
|
||||
style: TextStyle(color: LAYER_5),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
if (ndk.accounts.getPublicKey() == hexPubkey)
|
||||
Row(
|
||||
children: [
|
||||
BasicButton.text(
|
||||
"Logout",
|
||||
onTap: () {
|
||||
loginData.logout();
|
||||
context.go("/");
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
"Past Streams",
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
|
||||
),
|
||||
|
||||
RxFilter<Nip01Event>(
|
||||
key: Key("profile-streams:$hexPubkey"),
|
||||
relays: defaultRelays,
|
||||
filters: [
|
||||
Filter(kinds: [30_311], limit: 200, pTags: [hexPubkey]),
|
||||
Filter(kinds: [30_311], limit: 200, authors: [hexPubkey]),
|
||||
],
|
||||
builder: (ctx, state) {
|
||||
return StreamGrid(
|
||||
events: state ?? [],
|
||||
showLive: true,
|
||||
showEnded: true,
|
||||
showPlanned: true,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:chewie/chewie.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||
import 'package:zap_stream_flutter/main.dart';
|
||||
import 'package:zap_stream_flutter/theme.dart';
|
||||
import 'package:zap_stream_flutter/utils.dart';
|
||||
import 'package:zap_stream_flutter/widgets/button.dart';
|
||||
import 'package:zap_stream_flutter/widgets/chat.dart';
|
||||
import 'package:zap_stream_flutter/widgets/pill.dart';
|
||||
import 'package:zap_stream_flutter/widgets/profile.dart';
|
||||
import 'package:zap_stream_flutter/widgets/zap.dart';
|
||||
|
||||
class StreamPage extends StatefulWidget {
|
||||
final StreamEvent stream;
|
||||
@ -19,6 +22,7 @@ class StreamPage extends StatefulWidget {
|
||||
|
||||
class _StreamPage extends State<StreamPage> {
|
||||
VideoPlayerController? _controller;
|
||||
ChewieController? _chewieController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -34,10 +38,15 @@ class _StreamPage extends State<StreamPage> {
|
||||
_controller = VideoPlayerController.networkUrl(
|
||||
Uri.parse(url),
|
||||
httpHeaders: Map.from({"user-agent": userAgent}),
|
||||
videoPlayerOptions: VideoPlayerOptions(allowBackgroundPlayback: true),
|
||||
);
|
||||
() async {
|
||||
await _controller!.initialize();
|
||||
await _controller!.play();
|
||||
|
||||
_chewieController = ChewieController(
|
||||
videoPlayerController: _controller!,
|
||||
autoPlay: true,
|
||||
);
|
||||
setState(() {
|
||||
// nothing
|
||||
});
|
||||
@ -64,8 +73,8 @@ class _StreamPage extends State<StreamPage> {
|
||||
AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
child:
|
||||
_controller != null
|
||||
? VideoPlayer(_controller!)
|
||||
_chewieController != null
|
||||
? Chewie(controller: _chewieController!)
|
||||
: Container(color: LAYER_1),
|
||||
),
|
||||
Text(
|
||||
@ -76,15 +85,45 @@ class _StreamPage extends State<StreamPage> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
ProfileWidget.pubkey(widget.stream.info.host),
|
||||
PillWidget(
|
||||
color: LAYER_1,
|
||||
child: Text(
|
||||
"${widget.stream.info.participants} viewers",
|
||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
|
||||
),
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
BasicButton(
|
||||
Row(children: [Icon(Icons.bolt, size: 14), Text("Zap")]),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: PRIMARY_1,
|
||||
borderRadius: DEFAULT_BR,
|
||||
),
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
constraints: BoxConstraints.expand(),
|
||||
builder: (ctx) {
|
||||
return ZapWidget(
|
||||
pubkey: widget.stream.info.host,
|
||||
target: widget.stream.event,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
if (widget.stream.info.participants != null)
|
||||
PillWidget(
|
||||
color: LAYER_1,
|
||||
child: Text(
|
||||
"${widget.stream.info.participants} viewers",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Expanded(child: ChatWidget(stream: widget.stream)),
|
||||
],
|
||||
);
|
||||
|
Reference in New Issue
Block a user