Skip to content

Commit db1ee8a

Browse files
committed
add coshub featured cosplayers
1 parent 775e0b4 commit db1ee8a

File tree

10 files changed

+445
-180
lines changed

10 files changed

+445
-180
lines changed

lib/Backend/command_runner.dart

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:tail_app/Backend/command_queue.dart';
1010
import 'package:tail_app/Backend/dynamic_config.dart';
1111
import 'package:tail_app/Backend/logging_wrappers.dart';
1212
import 'package:tail_app/Backend/move_lists.dart';
13+
import 'package:tail_app/Frontend/utils.dart';
1314
import 'package:tail_app/constants.dart';
1415
import 'package:battery_plus/battery_plus.dart';
1516

@@ -34,16 +35,12 @@ class RunAction extends _$RunAction {
3435
// lets not kill the battery
3536
final int batteryLevel = await battery.batteryLevel;
3637
final bool batterySaver = await battery.isInBatterySaveMode;
37-
38+
3839
if (batteryLevel < 50 || batterySaver) {
3940
return;
4041
}
4142

42-
final DataSaverMode mode = await dataSaver.checkMode();
43-
final List<ConnectivityResult> connectivityResult = await (Connectivity().checkConnectivity());
44-
45-
// lets not burn through all of the data
46-
if (mode == DataSaverMode.enabled && connectivityResult.contains(ConnectivityResult.mobile)) {
43+
if (await isLimitedDataEnvironment()) {
4744
return;
4845
}
4946

lib/Backend/firebase.dart

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,81 @@ import 'dart:io';
33
import 'package:firebase_app_installations/firebase_app_installations.dart';
44
import 'package:firebase_core/firebase_core.dart';
55
import 'package:firebase_messaging/firebase_messaging.dart';
6+
import 'package:flutter_riverpod/flutter_riverpod.dart';
7+
import 'package:freezed_annotation/freezed_annotation.dart';
8+
import 'package:riverpod_annotation/riverpod_annotation.dart';
9+
import 'package:tail_app/firebase_options.dart';
10+
import 'package:cloud_firestore/cloud_firestore.dart';
611

712
import '../constants.dart';
8-
import '../firebase_options.dart';
913
import 'logging_wrappers.dart';
1014

11-
//TODO: Add setting
12-
//TODO: Add onboarding
15+
part 'firebase.g.dart';
16+
part 'firebase.freezed.dart';
17+
18+
@Riverpod(keepAlive: true)
19+
Future<void> initCosHubFirebase(Ref ref) async {
20+
await Firebase.initializeApp(
21+
name: 'CosHub', // Give your second app a custom name
22+
options: CosHubFirebaseOptions.currentPlatform,
23+
);
24+
}
25+
26+
@freezed
27+
abstract class CosHubPost with _$CosHubPost {
28+
const factory CosHubPost({
29+
required String id,
30+
required String url,
31+
String? character,
32+
required String thumbnailUrl,
33+
String? profileThumbnailUrl,
34+
required String username,
35+
}) = _CosHubPost;
36+
37+
factory CosHubPost.fromJson(Map<String, dynamic> json) => _$CosHubPostFromJson(json);
38+
}
39+
40+
@Riverpod()
41+
Future<List<CosHubPost>> getCosHubPosts(Ref ref) async {
42+
await ref.read(initCosHubFirebaseProvider.future);
43+
FirebaseApp secondaryApp = Firebase.app("CosHub");
44+
FirebaseFirestore firestore = FirebaseFirestore.instanceFor(app: secondaryApp);
45+
final appConstants = firestore.collection("appConstants");
46+
DocumentSnapshot<Map<String, dynamic>> featuredCosplayersUserIdsQuery = await appConstants.doc("featured_cosplayers").get();
47+
List<dynamic> featuredCosplayersUserIds = featuredCosplayersUserIdsQuery.data()!["user"] as List<dynamic>;
48+
final QuerySnapshot<Map<String, dynamic>> postsQuery = await firestore.collection("posts").where("userId", whereIn: featuredCosplayersUserIds).orderBy("createdAt", descending: true).limit(10).get();
49+
final QuerySnapshot<Map<String, dynamic>> usersQuery = await firestore.collection("users").where("id", whereIn: featuredCosplayersUserIds).get();
50+
51+
List<CosHubPost> mappedPosts = postsQuery.docs
52+
.map(
53+
(e) => e.data(),
54+
)
55+
.where(
56+
(element) {
57+
List<dynamic>? postImageUrls = element["postImageUrls"];
58+
return postImageUrls != null && postImageUrls.isNotEmpty;
59+
},
60+
).map(
61+
(postData) {
62+
Map<String, dynamic> userData = usersQuery.docs
63+
.firstWhere(
64+
(element) => element.data()["id"] == postData["userId"],
65+
)
66+
.data();
67+
CosHubPost cosHubPost = CosHubPost(
68+
id: postData["id"],
69+
url: " ",
70+
thumbnailUrl: postData["postImageUrls"][0],
71+
profileThumbnailUrl: userData["profilePicture"],
72+
username: userData["username"],
73+
character: postData["character"],
74+
);
75+
return cosHubPost;
76+
},
77+
).toList();
78+
return mappedPosts;
79+
}
80+
1381
//TODO: reset ID when disabled
1482
Future<void> configurePushNotifications() async {
1583
// Required before doing anything with firebase
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_riverpod/flutter_riverpod.dart';
3+
import 'package:tail_app/Backend/analytics.dart';
4+
import 'package:tail_app/Backend/firebase.dart';
5+
import 'package:tail_app/Frontend/Widgets/tail_blog.dart';
6+
import 'package:tail_app/Frontend/Widgets/tail_blog_image.dart';
7+
import 'package:tail_app/Frontend/Widgets/uwu_text.dart';
8+
import 'package:tail_app/Frontend/utils.dart';
9+
import 'package:tail_app/constants.dart';
10+
11+
class CoshubFeed extends ConsumerStatefulWidget {
12+
const CoshubFeed({super.key});
13+
14+
@override
15+
ConsumerState<CoshubFeed> createState() => _CoshubFeedState();
16+
}
17+
18+
List<CosHubPost> results = [];
19+
20+
class _CoshubFeedState extends ConsumerState<CoshubFeed> {
21+
FeedState feedState = FeedState.loading;
22+
23+
@override
24+
Widget build(BuildContext context) {
25+
return AnimatedCrossFade(
26+
alignment: Alignment.topCenter,
27+
firstChild: feedState == FeedState.loading
28+
? Center(
29+
child: CircularProgressIndicator(),
30+
)
31+
: [FeedState.noInternet, FeedState.error].contains(feedState)
32+
? const Center(
33+
child: Opacity(
34+
opacity: 0.5,
35+
child: Icon(
36+
Icons.signal_cellular_connected_no_internet_0_bar,
37+
size: 150,
38+
),
39+
),
40+
)
41+
: Container(),
42+
secondChild: ListView.builder(
43+
scrollDirection: Axis.horizontal,
44+
shrinkWrap: true,
45+
itemCount: results.length,
46+
itemBuilder: (BuildContext context, int index) {
47+
CosHubPost post = results[index];
48+
return Center(
49+
child: Padding(
50+
padding: const EdgeInsets.all(8.0),
51+
child: Card(
52+
clipBehavior: Clip.antiAlias,
53+
child: SizedBox(
54+
width: 300,
55+
child: Semantics(
56+
label: 'A button to view the CosHub post by: ${post.username}',
57+
child: InkWell(
58+
onTap: () async {
59+
await launchExternalUrl(url: post.url, analyticsLabel: "CosHub Post");
60+
},
61+
child: Stack(
62+
alignment: Alignment.bottomCenter,
63+
children: <Widget>[
64+
if (post.thumbnailUrl != "") ...[
65+
SizedBox.expand(
66+
child: TailBlogImage(
67+
url: post.thumbnailUrl,
68+
),
69+
),
70+
],
71+
Card(
72+
clipBehavior: Clip.antiAlias,
73+
margin: EdgeInsets.zero,
74+
elevation: 2,
75+
child: ListTile(
76+
//leading: Icon(feedItem.feedType.icon),
77+
trailing: const Icon(Icons.open_in_browser),
78+
title: Text(convertToUwU(post.username)), subtitle: post.character != null ? Text(convertToUwU(post.character!)) : null,
79+
leading: post.profileThumbnailUrl != null
80+
? ClipOval(
81+
child: SizedBox.fromSize(
82+
size: Size.fromRadius(24),
83+
child: TailBlogImage(
84+
url: post.profileThumbnailUrl!,
85+
),
86+
),
87+
)
88+
: null,
89+
),
90+
),
91+
],
92+
),
93+
),
94+
),
95+
),
96+
),
97+
),
98+
);
99+
},
100+
),
101+
crossFadeState: results.isNotEmpty ? CrossFadeState.showSecond : CrossFadeState.showFirst,
102+
duration: animationTransitionDuration,
103+
);
104+
}
105+
106+
@override
107+
void dispose() {
108+
super.dispose();
109+
//client.dispose();
110+
}
111+
112+
@override
113+
void initState() {
114+
super.initState();
115+
getFeed();
116+
}
117+
118+
Future<void> getFeed() async {
119+
if (results.isNotEmpty) {
120+
setState(() {
121+
feedState = FeedState.loaded;
122+
});
123+
return;
124+
}
125+
if (await isLimitedDataEnvironment()) {
126+
setState(() {
127+
feedState = FeedState.noInternet;
128+
});
129+
return;
130+
}
131+
List<CosHubPost> cosHubPosts = await ref.watch(getCosHubPostsProvider.future);
132+
setState(() {
133+
results = cosHubPosts;
134+
feedState = FeedState.loaded;
135+
});
136+
}
137+
}

0 commit comments

Comments
 (0)