[READ ONLY MIRROR] Open Source TikTok alternative built on AT Protocol github.com/sprksocial/client
flutter atproto video dart
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

è...

C3B 5c7d73e0 0f161b1b

+148 -131
+4 -4
README.md
··· 10 10 11 11 ## About Spark 12 12 13 - Spark Social PBC is building a decentralized social network on the AT Protocol, empowering users to share content without compromising privacy or control. With Spark, you own your data and decide how it's used. 13 + We are building a decentralized social network on the AT Protocol, empowering users to share content without compromising privacy or control. With Spark, you own your data and decide how it's used. 14 14 15 15 ## Core Principles 16 16 ··· 48 48 49 49 ### Prerequisites 50 50 51 - - Flutter SDK (3.7.2 or higher) 52 - - Dart SDK (3.0.0 or higher) 51 + - Flutter SDK 52 + - Dart SDK 53 53 - iOS/Android development environment 54 54 55 55 ### Installation 56 56 57 57 1. Clone this repository 58 58 ```bash 59 - git clone https://github.com/yourusername/spark-social.git 59 + git clone https://github.com/sprksocial/spark-front-end.git 60 60 ``` 61 61 62 62 2. Navigate to the project directory
+144 -127
lib/screens/home_screen.dart
··· 7 7 8 8 @override 9 9 Widget build(BuildContext context) { 10 + // Calculate proper bottom padding based on screen size and safe area 11 + final bottomPadding = MediaQuery.of(context).padding.bottom + 50; 12 + 10 13 return CupertinoPageScaffold( 11 14 backgroundColor: CupertinoColors.black, 12 15 child: SafeArea( 16 + bottom: false, 13 17 child: Column( 14 18 children: [ 15 19 const SizedBox(height: 10), ··· 54 58 55 59 // Video Feed (main content) 56 60 Expanded( 57 - child: PageView.builder( 58 - scrollDirection: Axis.vertical, 59 - itemCount: 10, // Sample videos 60 - itemBuilder: (context, index) { 61 - return VideoItem(index: index); 62 - }, 61 + child: Padding( 62 + // Dynamically calculate bottom padding based on device 63 + padding: EdgeInsets.only(bottom: bottomPadding), 64 + child: PageView.builder( 65 + scrollDirection: Axis.vertical, 66 + itemCount: 10, // Sample videos 67 + itemBuilder: (context, index) { 68 + return VideoItem(index: index); 69 + }, 70 + ), 63 71 ), 64 72 ), 65 73 ], ··· 76 84 77 85 @override 78 86 Widget build(BuildContext context) { 79 - return Stack( 80 - fit: StackFit.expand, 81 - children: [ 82 - // Video placeholder 83 - Container( 84 - color: index % 2 == 0 ? CupertinoColors.systemIndigo : CupertinoColors.systemPurple, 85 - child: Center( 86 - child: Icon( 87 - Ionicons.play_circle_outline, 88 - size: 80, 89 - color: CupertinoColors.white.withOpacity(0.7), 87 + return Container( 88 + // Use constraints to ensure the video fits within available space 89 + constraints: BoxConstraints( 90 + maxHeight: MediaQuery.of(context).size.height - 91 + MediaQuery.of(context).padding.top - 92 + 50 - // Top navigation height 93 + (MediaQuery.of(context).padding.bottom + 50), // Bottom nav height + safe area 94 + ), 95 + child: Stack( 96 + fit: StackFit.expand, 97 + children: [ 98 + // Video placeholder 99 + Container( 100 + color: index % 2 == 0 ? CupertinoColors.systemIndigo : CupertinoColors.systemPurple, 101 + child: Center( 102 + child: Icon( 103 + Ionicons.play_circle_outline, 104 + size: 80, 105 + color: CupertinoColors.white.withOpacity(0.7), 106 + ), 90 107 ), 91 108 ), 92 - ), 93 - 94 - // Video info 95 - Positioned( 96 - bottom: 20, 97 - left: 10, 98 - right: 70, 99 - child: Column( 100 - crossAxisAlignment: CrossAxisAlignment.start, 101 - children: [ 102 - Row( 103 - children: [ 104 - ClipOval( 105 - child: Container( 106 - width: 40, 107 - height: 40, 108 - color: CupertinoColors.systemGrey, 109 - child: const Center( 110 - child: Icon(Ionicons.person_outline, color: CupertinoColors.white), 109 + 110 + // Video info 111 + Positioned( 112 + bottom: 20, 113 + left: 10, 114 + right: 70, 115 + child: Column( 116 + crossAxisAlignment: CrossAxisAlignment.start, 117 + children: [ 118 + Row( 119 + children: [ 120 + ClipOval( 121 + child: Container( 122 + width: 40, 123 + height: 40, 124 + color: CupertinoColors.systemGrey, 125 + child: const Center( 126 + child: Icon(Ionicons.person_outline, color: CupertinoColors.white), 127 + ), 111 128 ), 112 129 ), 113 - ), 114 - const SizedBox(width: 10), 115 - const Text( 116 - '@username', 117 - style: TextStyle( 130 + const SizedBox(width: 10), 131 + const Text( 132 + '@username', 133 + style: TextStyle( 134 + color: CupertinoColors.white, 135 + fontWeight: FontWeight.bold, 136 + ), 137 + ), 138 + const SizedBox(width: 10), 139 + Container( 140 + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), 141 + decoration: BoxDecoration( 142 + border: Border.all(color: CupertinoColors.white), 143 + borderRadius: BorderRadius.circular(10), 144 + ), 145 + child: const Text( 146 + 'Follow', 147 + style: TextStyle( 148 + color: CupertinoColors.white, 149 + fontSize: 12, 150 + ), 151 + ), 152 + ), 153 + ], 154 + ), 155 + const SizedBox(height: 10), 156 + const Text( 157 + 'Video caption goes here #tiktok #viral #trending', 158 + style: TextStyle(color: CupertinoColors.white), 159 + maxLines: 2, 160 + overflow: TextOverflow.ellipsis, 161 + ), 162 + ], 163 + ), 164 + ), 165 + 166 + // Right side actions 167 + Positioned( 168 + right: 10, 169 + bottom: 100, 170 + child: Column( 171 + children: [ 172 + // Like button 173 + Column( 174 + children: [ 175 + const Icon( 176 + Ionicons.heart_outline, 118 177 color: CupertinoColors.white, 119 - fontWeight: FontWeight.bold, 178 + size: 30, 120 179 ), 121 - ), 122 - const SizedBox(width: 10), 123 - Container( 124 - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), 125 - decoration: BoxDecoration( 126 - border: Border.all(color: CupertinoColors.white), 127 - borderRadius: BorderRadius.circular(10), 128 - ), 129 - child: const Text( 130 - 'Follow', 131 - style: TextStyle( 180 + const SizedBox(height: 4), 181 + Text( 182 + '${(index + 1) * 1000}', 183 + style: const TextStyle( 132 184 color: CupertinoColors.white, 133 185 fontSize: 12, 134 186 ), 135 187 ), 136 - ), 137 - ], 138 - ), 139 - const SizedBox(height: 10), 140 - const Text( 141 - 'Video caption goes here #tiktok #viral #trending', 142 - style: TextStyle(color: CupertinoColors.white), 143 - maxLines: 2, 144 - overflow: TextOverflow.ellipsis, 145 - ), 146 - ], 147 - ), 148 - ), 149 - 150 - // Right side actions 151 - Positioned( 152 - right: 10, 153 - bottom: 100, 154 - child: Column( 155 - children: [ 156 - // Like button 157 - Column( 158 - children: [ 159 - const Icon( 160 - Ionicons.heart_outline, 161 - color: CupertinoColors.white, 162 - size: 30, 163 - ), 164 - const SizedBox(height: 4), 165 - Text( 166 - '${(index + 1) * 1000}', 167 - style: const TextStyle( 188 + ], 189 + ), 190 + const SizedBox(height: 20), 191 + // Comment button 192 + Column( 193 + children: [ 194 + const Icon( 195 + Ionicons.chatbubble_outline, 168 196 color: CupertinoColors.white, 169 - fontSize: 12, 197 + size: 30, 198 + ), 199 + const SizedBox(height: 4), 200 + Text( 201 + '${(index + 1) * 100}', 202 + style: const TextStyle( 203 + color: CupertinoColors.white, 204 + fontSize: 12, 205 + ), 170 206 ), 171 - ), 172 - ], 173 - ), 174 - const SizedBox(height: 20), 175 - // Comment button 176 - Column( 177 - children: [ 178 - const Icon( 179 - Ionicons.chatbubble_outline, 180 - color: CupertinoColors.white, 181 - size: 30, 182 - ), 183 - const SizedBox(height: 4), 184 - Text( 185 - '${(index + 1) * 100}', 186 - style: const TextStyle( 207 + ], 208 + ), 209 + const SizedBox(height: 20), 210 + // Share button 211 + Column( 212 + children: [ 213 + const Icon( 214 + Ionicons.arrow_redo_outline, 187 215 color: CupertinoColors.white, 188 - fontSize: 12, 216 + size: 30, 189 217 ), 190 - ), 191 - ], 192 - ), 193 - const SizedBox(height: 20), 194 - // Share button 195 - Column( 196 - children: [ 197 - const Icon( 198 - Ionicons.arrow_redo_outline, 199 - color: CupertinoColors.white, 200 - size: 30, 201 - ), 202 - const SizedBox(height: 4), 203 - Text( 204 - '${(index + 1) * 10}', 205 - style: const TextStyle( 206 - color: CupertinoColors.white, 207 - fontSize: 12, 218 + const SizedBox(height: 4), 219 + Text( 220 + '${(index + 1) * 10}', 221 + style: const TextStyle( 222 + color: CupertinoColors.white, 223 + fontSize: 12, 224 + ), 208 225 ), 209 - ), 210 - ], 211 - ), 212 - ], 226 + ], 227 + ), 228 + ], 229 + ), 213 230 ), 214 - ), 215 - ], 231 + ], 232 + ), 216 233 ); 217 234 } 218 235 }