refactor: move app entry point

This commit is contained in:
2025-05-21 13:33:15 +01:00
parent 99ec8cfbf7
commit 825152c6bf
34 changed files with 281 additions and 221 deletions

128
lib/app.dart Normal file
View File

@ -0,0 +1,128 @@
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/pages/category.dart';
import 'package:zap_stream_flutter/pages/hashtag.dart';
import 'package:zap_stream_flutter/pages/home.dart';
import 'package:zap_stream_flutter/pages/login.dart';
import 'package:zap_stream_flutter/pages/login_input.dart';
import 'package:zap_stream_flutter/pages/new_account.dart';
import 'package:zap_stream_flutter/pages/profile.dart';
import 'package:zap_stream_flutter/pages/settings_profile.dart';
import 'package:zap_stream_flutter/pages/stream.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';
import 'package:zap_stream_flutter/widgets/header.dart';
void runZapStream() {
runApp(
MaterialApp.router(
title: "zap.stream",
supportedLocales: AppLocaleUtils.supportedLocales,
localizationsDelegates: GlobalMaterialLocalizations.delegates,
theme: ThemeData.localize(
ThemeData(colorScheme: ColorScheme.dark(), highlightColor: PRIMARY_1),
TextTheme(),
),
routerConfig: GoRouter(
routes: [
ShellRoute(
observers: [routeObserver],
builder:
(context, state, child) => SafeArea(
child: Scaffold(body: child, backgroundColor: Colors.black),
),
routes: [
GoRoute(path: "/", builder: (ctx, state) => HomePage()),
ShellRoute(
builder: (context, state, child) {
return Container(
margin: EdgeInsets.only(top: 50),
padding: EdgeInsets.symmetric(horizontal: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 20,
children: [
Center(
child: Image.asset("assets/logo.png", height: 150),
),
child,
],
),
);
},
routes: [
GoRoute(
path: "/login",
builder: (ctx, state) => LoginPage(),
routes: [
GoRoute(
path: "key",
builder: (ctx, state) => LoginInputPage(),
),
GoRoute(
path: "new",
builder: (context, state) => NewAccountPage(),
),
],
),
],
),
GoRoute(
path: StreamPage.path,
builder: (ctx, state) {
if (state.extra is StreamEvent) {
return StreamPage(stream: state.extra as StreamEvent);
} else {
throw UnimplementedError();
}
},
),
GoRoute(
path: "/p/:id",
builder: (ctx, state) {
return ProfilePage(pubkey: state.pathParameters["id"]!);
},
),
GoRoute(
path: "/t/:id",
builder: (context, state) {
return HashtagPage(tag: state.pathParameters["id"]!);
},
),
GoRoute(
path: "/category/:id",
builder: (context, state) {
return CategoryPage(
category: state.pathParameters["id"]!,
info: state.extra as GameInfo?,
);
},
),
ShellRoute(
observers: [routeObserver],
builder:
(context, state, child) =>
Column(children: [HeaderWidget(), child]),
routes: [
GoRoute(
path: "/settings",
builder: (context, state) => SizedBox(),
routes: [
GoRoute(
path: "profile",
builder: (context, state) => SettingsProfilePage(),
),
],
),
],
),
],
),
],
),
),
);
}

73
lib/const.dart Normal file
View File

@ -0,0 +1,73 @@
import 'package:amberflutter/amberflutter.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:ndk/ndk.dart';
import 'package:ndk_amber/ndk_amber.dart';
import 'package:ndk_objectbox/ndk_objectbox.dart';
import 'package:ndk_rust_verifier/ndk_rust_verifier.dart';
import 'package:zap_stream_flutter/login.dart';
class NoVerify extends EventVerifier {
@override
Future<bool> verify(Nip01Event event) {
return Future.value(true);
}
}
final ndkCache = DbObjectBox();
final eventVerifier = kDebugMode ? NoVerify() : RustEventVerifier();
var ndk = Ndk(
NdkConfig(
eventVerifier: eventVerifier,
cache: ndkCache,
bootstrapRelays: defaultRelays,
//engine: NdkEngine.JIT,
),
);
const userAgent = "zap.stream/1.0";
const defaultRelays = [
"wss://nos.lol",
"wss://relay.damus.io",
"wss://relay.primal.net",
"wss://relay.snort.social",
"wss://relay.fountain.fm",
];
const searchRelays = ["wss://relay.nostr.band", "wss://search.nos.today"];
final loginData = LoginData();
final RouteObserver<ModalRoute<void>> routeObserver =
RouteObserver<ModalRoute<void>>();
Future<void> initLogin() async {
// reload / cache login data
loginData.addListener(() {
if (loginData.value != null) {
final pubkey = loginData.value!.pubkey;
if (!ndk.accounts.hasAccount(pubkey)) {
switch (loginData.value!.type) {
case AccountType.privateKey:
ndk.accounts.loginPrivateKey(
pubkey: pubkey,
privkey: loginData.value!.privateKey!,
);
case AccountType.externalSigner:
ndk.accounts.loginExternalSigner(
signer: AmberEventSigner(
publicKey: pubkey,
amberFlutterDS: AmberFlutterDS(Amberflutter()),
),
);
case AccountType.publicKey:
ndk.accounts.loginPublicKey(pubkey: pubkey);
}
}
ndk.metadata.loadMetadata(pubkey);
ndk.follows.getContactList(pubkey);
} else {
ndk.accounts.logout();
}
});
await loginData.load();
}

View File

@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
import 'package:zap_stream_flutter/app.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
LocaleSettings.useDeviceLocale();
// FCM DELETE
await initLogin();
runZapStream();
}

View File

@ -119,4 +119,4 @@ class LoginData extends ValueNotifier<LoginAccount?> {
}
}
}
}
}

View File

@ -1,201 +1,14 @@
import 'package:amberflutter/amberflutter.dart';
import 'package:flutter/foundation.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:ndk/ndk.dart';
import 'package:ndk_amber/ndk_amber.dart';
import 'package:ndk_objectbox/ndk_objectbox.dart';
import 'package:ndk_rust_verifier/ndk_rust_verifier.dart';
import 'package:zap_stream_flutter/app.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/pages/category.dart';
import 'package:zap_stream_flutter/pages/hashtag.dart';
import 'package:zap_stream_flutter/pages/login.dart';
import 'package:zap_stream_flutter/pages/login_input.dart';
import 'package:zap_stream_flutter/pages/new_account.dart';
import 'package:zap_stream_flutter/pages/profile.dart';
import 'package:zap_stream_flutter/pages/settings_profile.dart';
import 'package:zap_stream_flutter/pages/stream.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';
import 'package:zap_stream_flutter/widgets/header.dart';
import 'login.dart';
import 'pages/home.dart';
class NoVerify extends EventVerifier {
@override
Future<bool> verify(Nip01Event event) {
return Future.value(true);
}
}
final ndkCache = DbObjectBox();
final eventVerifier = kDebugMode ? NoVerify() : RustEventVerifier();
var ndk = Ndk(
NdkConfig(
eventVerifier: eventVerifier,
cache: ndkCache,
bootstrapRelays: defaultRelays,
//engine: NdkEngine.JIT,
),
);
const userAgent = "zap.stream/1.0";
const defaultRelays = [
"wss://nos.lol",
"wss://relay.damus.io",
"wss://relay.primal.net",
"wss://relay.snort.social",
"wss://relay.fountain.fm",
];
const searchRelays = ["wss://relay.nostr.band", "wss://search.nos.today"];
final loginData = LoginData();
final RouteObserver<ModalRoute<void>> routeObserver =
RouteObserver<ModalRoute<void>>();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
LocaleSettings.useDeviceLocale();
await Firebase.initializeApp();
await initLogin();
// reload / cache login data
loginData.addListener(() {
if (loginData.value != null) {
final pubkey = loginData.value!.pubkey;
if (!ndk.accounts.hasAccount(pubkey)) {
switch (loginData.value!.type) {
case AccountType.privateKey:
ndk.accounts.loginPrivateKey(
pubkey: pubkey,
privkey: loginData.value!.privateKey!,
);
case AccountType.externalSigner:
ndk.accounts.loginExternalSigner(
signer: AmberEventSigner(
publicKey: pubkey,
amberFlutterDS: AmberFlutterDS(Amberflutter()),
),
);
case AccountType.publicKey:
ndk.accounts.loginPublicKey(pubkey: pubkey);
}
}
ndk.metadata.loadMetadata(pubkey);
ndk.follows.getContactList(pubkey);
} else {
ndk.accounts.logout();
}
});
await loginData.load();
runApp(
MaterialApp.router(
title: "zap.stream",
supportedLocales: AppLocaleUtils.supportedLocales,
localizationsDelegates: GlobalMaterialLocalizations.delegates,
theme: ThemeData.localize(
ThemeData(colorScheme: ColorScheme.dark(), highlightColor: PRIMARY_1),
TextTheme(),
),
routerConfig: GoRouter(
routes: [
ShellRoute(
observers: [routeObserver],
builder:
(context, state, child) => SafeArea(
child: Scaffold(body: child, backgroundColor: Colors.black),
),
routes: [
GoRoute(path: "/", builder: (ctx, state) => HomePage()),
ShellRoute(
builder: (context, state, child) {
return Container(
margin: EdgeInsets.only(top: 50),
padding: EdgeInsets.symmetric(horizontal: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 20,
children: [
Center(
child: Image.asset("assets/logo.png", height: 150),
),
child,
],
),
);
},
routes: [
GoRoute(
path: "/login",
builder: (ctx, state) => LoginPage(),
routes: [
GoRoute(
path: "key",
builder: (ctx, state) => LoginInputPage(),
),
GoRoute(
path: "new",
builder: (context, state) => NewAccountPage(),
),
],
),
],
),
GoRoute(
path: StreamPage.path,
builder: (ctx, state) {
if (state.extra is StreamEvent) {
return StreamPage(stream: state.extra as StreamEvent);
} else {
throw UnimplementedError();
}
},
),
GoRoute(
path: "/p/:id",
builder: (ctx, state) {
return ProfilePage(pubkey: state.pathParameters["id"]!);
},
),
GoRoute(
path: "/t/:id",
builder: (context, state) {
return HashtagPage(tag: state.pathParameters["id"]!);
},
),
GoRoute(
path: "/category/:id",
builder: (context, state) {
return CategoryPage(
category: state.pathParameters["id"]!,
info: state.extra as GameInfo?,
);
},
),
ShellRoute(
observers: [routeObserver],
builder:
(context, state, child) =>
Column(children: [HeaderWidget(), child]),
routes: [
GoRoute(
path: "/settings",
builder: (context, state) => SizedBox(),
routes: [
GoRoute(
path: "profile",
builder: (context, state) => SettingsProfilePage(),
),
],
),
],
),
],
),
],
),
),
);
runZapStream();
}

View File

@ -5,7 +5,7 @@ import 'package:flutter/widgets.dart';
import 'package:go_router/go_router.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/login.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';
import 'package:zap_stream_flutter/widgets/button.dart';

View File

@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/i18n/strings.g.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/utils.dart';
import 'package:zap_stream_flutter/widgets/button.dart';

View File

@ -5,7 +5,7 @@ import 'package:ndk/shared/nips/nip01/bip340.dart';
import 'package:ndk/shared/nips/nip01/key_pair.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/login.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/widgets/avatar_upload.dart';
import 'package:zap_stream_flutter/widgets/button.dart';

View File

@ -3,7 +3,7 @@ import 'package:go_router/go_router.dart';
import 'package:ndk/ndk.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/imgproxy.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/rx_filter.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:ndk/ndk.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/widgets/avatar_upload.dart';
import 'package:zap_stream_flutter/widgets/button.dart';

View File

@ -6,7 +6,7 @@ import 'package:ndk/ndk.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/imgproxy.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/rx_filter.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';

View File

@ -5,7 +5,7 @@ import 'dart:developer' as developer;
import 'package:flutter/widgets.dart';
import 'package:ndk/ndk.dart';
import 'package:rxdart/rxdart.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
/// Reactive filter which builds the widget with a snapshot of the data
class RxFilter<T> extends StatefulWidget {

View File

@ -2,7 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
class AvatarUpload extends StatefulWidget {

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/widgets/button.dart';

View File

@ -2,7 +2,7 @@ import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:ndk/ndk.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/rx_filter.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';

View File

@ -2,7 +2,7 @@ import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:ndk/ndk.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/rx_filter.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';

View File

@ -3,7 +3,7 @@ import 'package:flutter/widgets.dart';
import 'package:ndk/entities.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/imgproxy.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';
import 'package:zap_stream_flutter/widgets/profile.dart';

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:ndk/ndk.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/rx_filter.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';

View File

@ -1,7 +1,7 @@
import 'package:duration/duration.dart';
import 'package:flutter/material.dart';
import 'package:ndk/ndk.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';
import 'package:zap_stream_flutter/widgets/button_follow.dart';

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:ndk/ndk.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';
import 'package:zap_stream_flutter/widgets/countdown.dart';

View File

@ -3,7 +3,7 @@ import 'package:duration/duration.dart';
import 'package:flutter/widgets.dart';
import 'package:ndk/ndk.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/widgets/profile.dart';

View File

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:ndk/ndk.dart';
import 'package:ndk/shared/nips/nip19/nip19.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';
import 'package:zap_stream_flutter/widgets/avatar.dart';

View File

@ -3,7 +3,7 @@ import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart';
import 'package:ndk/shared/nips/nip19/nip19.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/widgets/avatar.dart';

View File

@ -1,7 +1,7 @@
import 'package:flutter/widgets.dart';
import 'package:ndk/domain_layer/entities/nip_51_list.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/widgets/button.dart';

View File

@ -2,7 +2,7 @@ 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/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/widgets/avatar.dart';
class ProfileLoaderWidget extends StatelessWidget {

View File

@ -2,7 +2,7 @@ import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
import 'package:flutter/foundation.dart' as foundation;
import 'package:flutter/widgets.dart';
import 'package:ndk/entities.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
final emojiPickerConfig = Config(

View File

@ -2,7 +2,7 @@ import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:ndk/ndk.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';
import 'package:zap_stream_flutter/widgets/stream_tile.dart';

View File

@ -3,7 +3,7 @@ import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:share_plus/share_plus.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';
import 'package:zap_stream_flutter/widgets/button.dart';

View File

@ -1,6 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/imgproxy.dart';

View File

@ -2,7 +2,7 @@ import 'package:chewie/chewie.dart';
import 'package:flutter/widgets.dart';
import 'package:video_player/video_player.dart';
import 'package:zap_stream_flutter/imgproxy.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
class VideoPlayerWidget extends StatefulWidget {
final String url;

View File

@ -9,7 +9,7 @@ import 'package:ndk/ndk.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:zap_stream_flutter/i18n/strings.g.dart';
import 'package:zap_stream_flutter/main.dart';
import 'package:zap_stream_flutter/const.dart';
import 'package:zap_stream_flutter/theme.dart';
import 'package:zap_stream_flutter/utils.dart';
import 'package:zap_stream_flutter/widgets/button.dart';