Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http" android:host="forum.ghse.de" />
<data android:scheme="https" />
</intent-filter>
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
Expand Down
15 changes: 15 additions & 0 deletions ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>FlutterDeepLinkingEnabled</key>
<true/>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>forum.ghse.de</string>
<key>CFBundleURLSchemes</key>
<array>
<string>customscheme</string>
</array>
</dict>
</array>
<key>NSPhotoLibraryUsageDescription</key>
<string>Upload images for screen background</string>
<key>NSCameraUsageDescription</key>
Expand Down
45 changes: 42 additions & 3 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,54 @@
import 'package:flutter/material.dart';
import 'package:forum/palette.dart';
import 'package:forum/views/splash_page.dart';
import 'package:forum/services/local_services.dart';
import 'package:forum/views/home_page.dart';
import 'package:forum/views/login_page.dart';
import 'package:forum/views/post_page.dart';
import 'package:forum/views/search_page.dart';
import 'package:forum/views/user_page.dart';

import 'package:go_router/go_router.dart';

import 'models/post.dart';

void main() => runApp(const MyApp());

final GoRouter _router = GoRouter(
redirect: (BuildContext context, GoRouterState state) async {
final bool isAuthed = await LocalServices().isAuth();
if (!isAuthed) {
return '/login';
}
},
routes: [
GoRoute(path: '/login', builder: (context, state) => const LoginPage()),
GoRoute(
path: '/',
builder: (context, state) => const HomePage(),
routes: [
GoRoute(
name: 'post',
path: 'post/:id',
builder: (context, state) =>
FullScreenPostWidget(id: state.params['id']!)),
GoRoute(
name: 'search',
path: 'search',
builder: (context, state) => const SearchPage()),
GoRoute(
name: 'user',
path: 'user/:id',
builder: (context, state) =>
UserPage(userId: state.params['id']!)),
]),
]);

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
return MaterialApp.router(
title: 'GHSE Forum',
theme: ThemeData(
primarySwatch: Palette.BlueToDark,
Expand All @@ -20,7 +59,7 @@ class MyApp extends StatelessWidget {
selectionHandleColor: Palette.OrangeToDark,
),
),
home: const SplashPage(),
routerConfig: _router,
);
}
}
1 change: 0 additions & 1 deletion lib/palette.dart
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,3 @@ class Palette {
},
);
} // you can define define int 500 as the default shade and add your lighter tints above and darker tints below.

36 changes: 23 additions & 13 deletions lib/services/local_services.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,57 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
const storage = FlutterSecureStorage();

class LocalServices {
Future<String?> getUserName() async{
Future<String?> getUserName() async {
return await storage.readAll().then((value) => value['user_name']);
}

Future<String?> getUserId() async{
Future<String?> getUserId() async {
return await storage.readAll().then((value) => value['user_id']);
}

Future<String?> getToken() async{
Future<String?> getToken() async {
return await storage.readAll().then((value) => value['token']);
}

Future<String?> getExpiration() async{
Future<String?> getExpiration() async {
return await storage.readAll().then((value) => value['expiration']);
}

Future<bool> isAuth() async {
if ((await getToken() != null) &&
(DateTime.parse((await getExpiration())!).isAfter(DateTime.now()))) {
return true;
}
return false;
}

Future<void> writeUserData(
String userName, String userId, String token, String expiration) async {
await storage.write(key: 'user_name', value: userName);
await storage.write(key: 'user_id', value: userId);
await storage.write(key: 'token', value: token);
await storage.write(key: 'expiration', value: expiration);
}

deleteUserData() async {
await storage.deleteAll();
}
String getFormatedDate(DateTime date) {
String formatedDate = '';

String getFormattedDate(DateTime date) {
String formattedDate = '';
if (date.isAfter(DateTime.now().subtract(const Duration(days: 1)))) {
formatedDate = '${date.hour}:';
formattedDate = '${date.hour}:';
if (date.hour < 10) {
formatedDate = '0$formatedDate';
formattedDate = '0$formattedDate';
}
if (date.minute < 10) {
formatedDate = '${formatedDate}0${date.minute}';
formattedDate = '${formattedDate}0${date.minute}';
} else {
formatedDate = '$formatedDate${date.minute}';
formattedDate = '$formattedDate${date.minute}';
}
} else {
formatedDate = '${date.day}/${date.month}/${date.year}';
formattedDate = '${date.day}/${date.month}/${date.year}';
}
return formatedDate;
return formattedDate;
}
}
}
58 changes: 31 additions & 27 deletions lib/services/remote_services.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import 'package:forum/services/local_services.dart';
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';


final LocalServices localServices = LocalServices();

class RemoteService {
Expand All @@ -22,7 +21,6 @@ class RemoteService {
'Accept': 'application/json',
};


Future<List<Post>?> getPostsPage(int page) async {
var url = Uri.parse('${apiUrl}post/page/$page');
var token = await localServices.getToken();
Expand All @@ -38,8 +36,8 @@ class RemoteService {

Future<void> register(String userName, String password) async {
var url = Uri.parse('${apiUrl}auth/register');
final body = jsonEncode(
Auth(userName: userName, password: password).toJson());
final body =
jsonEncode(Auth(userName: userName, password: password).toJson());

final response = await http.post(url, body: body, headers: headers);
if (response.statusCode == 200) {
Expand All @@ -53,8 +51,8 @@ class RemoteService {

Future<AuthResponse> getToken(String userName, String password) async {
var url = Uri.parse('${apiUrl}auth/authenticate');
final body = jsonEncode(
Auth(userName: userName, password: password).toJson());
final body =
jsonEncode(Auth(userName: userName, password: password).toJson());
headers.remove('Authorization');

final response = await http.post(url, body: body, headers: headers);
Expand All @@ -75,12 +73,7 @@ class RemoteService {
var token = await localServices.getToken();
headers.addAll({'Authorization': 'Bearer $token'});

final body = jsonEncode(
{
"title": title,
"content": content
}
);
final body = jsonEncode({"title": title, "content": content});

final http.Response response = await http.post(
url,
Expand Down Expand Up @@ -145,12 +138,8 @@ class RemoteService {
var url = Uri.parse('${apiUrl}comment/add/');
var token = await localServices.getToken();
headers.addAll({'Authorization': 'Bearer $token'});
var response = await http.post(url, headers: headers, body: jsonEncode(
{
"content": text,
"post_id": id
}
));
var response = await http.post(url,
headers: headers, body: jsonEncode({"content": text, "post_id": id}));
if (response.statusCode == 200) {
return true;
} else {
Expand Down Expand Up @@ -189,9 +178,10 @@ class RemoteService {
var url = Uri.parse('${apiUrl}post/$postId');
var token = await localServices.getToken();
headers.addAll({'Authorization': 'Bearer $token'});
var response = await http.put(
url, headers: headers, body: jsonEncode(post.toJson()));
if (response.statusCode == 200) {} else {
var response =
await http.put(url, headers: headers, body: jsonEncode(post.toJson()));
if (response.statusCode == 200) {
} else {
throw Exception('Failed to update post');
}
}
Expand All @@ -201,7 +191,8 @@ class RemoteService {
var token = await localServices.getToken();
headers.addAll({'Authorization': 'Bearer $token'});
var response = await http.delete(url, headers: headers);
if (response.statusCode == 200) {} else {
if (response.statusCode == 200) {
} else {
throw Exception('Failed to delete post');
}
}
Expand Down Expand Up @@ -240,12 +231,12 @@ class RemoteService {
headers.addAll({'Authorization': 'Bearer $token'});
var response = await http.put(url, headers: headers);

if (response.statusCode == 200) {} else {
if (response.statusCode == 200) {
} else {
throw Exception('Failed to update bio');
}
}


Future<void> uploadProfileImage(File file) async {
var uri = Uri.parse('${apiUrl}file/profile');
var token = await localServices.getToken();
Expand All @@ -258,12 +249,12 @@ class RemoteService {
request.files.add(await http.MultipartFile.fromPath('file', file.path,
contentType: MediaType('image', file.path.split('.').last)));
final response = await request.send();
if(response.statusCode != 200) {
if (response.statusCode != 200) {
throw Exception('Failed to upload image');
}
}

Future<void> uploadImage(File file,String id) async {
Future<void> uploadImage(File file, String id) async {
var uri = Uri.parse('${apiUrl}file/post/$id');
var token = await localServices.getToken();
final headers = {
Expand All @@ -275,8 +266,21 @@ class RemoteService {
request.files.add(await http.MultipartFile.fromPath('file', file.path,
contentType: MediaType('image', file.path.split('.').last)));
final response = await request.send();
if(response.statusCode != 200) {
if (response.statusCode != 200) {
throw Exception('Failed to upload image');
}
}

Future<Post> getPost(String id) async {
var url = Uri.parse('${apiUrl}post/$id');
var token = await localServices.getToken();
headers.addAll({'Authorization': 'Bearer $token'});
var response = await http.get(url, headers: headers);
if (response.statusCode == 200) {
var json = response.body;
return Post.fromJson(jsonDecode(json));
} else {
throw Exception('Failed to load post');
}
}
}
Loading