Compare commits

..

9 commits

23 changed files with 681 additions and 253 deletions

View file

@ -1,3 +1,58 @@
# dth-pingpong-mobileapp
>
> Minimum supported Android API: 28 (Android 9).\
> Minimum required iOS version: 14
>
Flutter application for ping pong score tracking. supports friends, elo tracking, match creation and planning.
Mobile application for ping pong score tracking. supports friends ,elo tracking, match creation and planning.
![lang](https://img.shields.io/badge/Flutter-02569B?style=for-the-badge&logo=flutter&logoColor=white) ![os1](https://img.shields.io/badge/Android-3DDC84?style=for-the-badge&logo=android&logoColor=white)
---
# Installing
Installation options are available for major mobile platforms. Although we mainly support android, all the features are cross-compatible with iOS
### Stable release channel (Android only)
Grab one of the builds from the releases page or run:
```bash
flutter build apk
```
Production artifacts will be found in the `build\app\outputs\apk\` directory.
**RRC (Rolling Release Channel)**
There's also a Rolling release available as pre-release builds. They will be released in a much quicker update ring (every other commit i'd assume) and are mostly debug builds so they'll be very heavy and *likely* broken.
### Building instructions (Android)
Make sure you have [Flutter](https://flutter.dev/), [Android Studio](https://developer.android.com/studio), and [Visual Studio Code](https://code.visualstudio.com/) installed. Install the suggested Flutter, Dart, and linting extensions in Visual Studio Code.
Run the following commands to ensure all dependencies are met:
```bash
flutter doctor
```
You'll be guided through a first-time setup that checks for platform tools, dependencies, and missing components.
Once the setup is complete you can navigate to the repo folder and run
```bash
flutter run
```
If you want to build debug you can also run
```bash
flutter build apk --debug
```
Build artifacts for Android are saved under `build\app\outputs\apk`.
### Building instructions (iOS)
**MAJOR WORD OF WARNING: iOS builds are NOT officially supported, and we have NO clue as to why or how certain things just break on the xCode build (namely some icons and some api calls). if you encounter these issues you are free to patch them, and, if you seem fit, hit me up with a PR**
Make sure you have [Flutter](https://flutter.dev/), [xCode and Apple Developer Tools](https://apps.apple.com/en/app/xcode/id497799835?mt=12), [cocoapods](https://formulae.brew.sh/formula/cocoapods), and [Visual Studio Code](https://code.visualstudio.com/) installed.
Install the suggested Flutter, Dart, and linting extensions in Visual Studio Code and set up xcode for "iOS on iphone" developement. Once that is done, go in the project's folder and run the following command to ensure that your build environment is properly configured, any missing component will be highlighted
```bash
flutter doctor
```
Once you've done that, from the same terminal, run this command to generate a .IPA file - once you're done it's a matter of sideloading it to your device. since i've never owned an apple device i have no idea how to do that. iOS artifacts are saved in `build/ios/runner/`.
```bash
flutter build ios
```

BIN
ios/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View file

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

44
ios/Podfile Normal file
View file

@ -0,0 +1,44 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

23
ios/Podfile.lock Normal file
View file

@ -0,0 +1,23 @@
PODS:
- Flutter (1.0.0)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
DEPENDENCIES:
- Flutter (from `Flutter`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
EXTERNAL SOURCES:
Flutter:
:path: Flutter
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
SPEC CHECKSUMS:
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
COCOAPODS: 1.16.2

View file

@ -10,7 +10,9 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
4ECA18A68D772963A75CDDEE /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 664C6953382FB54D8ADFAA15 /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
860A7C4827A4A1FA258EE3B0 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A33A52767F410023C3017843 /* Pods_RunnerTests.framework */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
@ -42,12 +44,19 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
1D683FDEB78EA33536EDD9B0 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
2310337C49F4840CC13DECEC /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
2BD08DFC2DFC2958AE95FAD5 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
664C6953382FB54D8ADFAA15 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7339FE983199E9675039DE4E /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
8D54E1F7566A817BB3B988AC /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
9702D4B740EAB4624B982FE0 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -55,19 +64,38 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A33A52767F410023C3017843 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
035979494952341CA3553103 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
860A7C4827A4A1FA258EE3B0 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4ECA18A68D772963A75CDDEE /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
2F1367A0823D5A1C2FD30B1E /* Frameworks */ = {
isa = PBXGroup;
children = (
664C6953382FB54D8ADFAA15 /* Pods_Runner.framework */,
A33A52767F410023C3017843 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
@ -76,6 +104,20 @@
path = RunnerTests;
sourceTree = "<group>";
};
803619556C668AF928FE7E28 /* Pods */ = {
isa = PBXGroup;
children = (
2310337C49F4840CC13DECEC /* Pods-Runner.debug.xcconfig */,
7339FE983199E9675039DE4E /* Pods-Runner.release.xcconfig */,
2BD08DFC2DFC2958AE95FAD5 /* Pods-Runner.profile.xcconfig */,
1D683FDEB78EA33536EDD9B0 /* Pods-RunnerTests.debug.xcconfig */,
8D54E1F7566A817BB3B988AC /* Pods-RunnerTests.release.xcconfig */,
9702D4B740EAB4624B982FE0 /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@ -94,6 +136,8 @@
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
803619556C668AF928FE7E28 /* Pods */,
2F1367A0823D5A1C2FD30B1E /* Frameworks */,
);
sourceTree = "<group>";
};
@ -128,8 +172,10 @@
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
B52AA023DC4D626077351632 /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
035979494952341CA3553103 /* Frameworks */,
);
buildRules = (
);
@ -145,12 +191,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
B9DF9E6804910D262BD7E7EA /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
64EEB9E634C86FA592F486D2 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -238,6 +286,23 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
64EEB9E634C86FA592F486D2 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@ -253,6 +318,50 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
B52AA023DC4D626077351632 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
B9DF9E6804910D262BD7E7EA /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -327,6 +436,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -361,7 +471,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = R28MH57GSC;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -370,6 +483,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = dth.innodesi.pingpongapp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
@ -378,6 +492,7 @@
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1D683FDEB78EA33536EDD9B0 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@ -395,6 +510,7 @@
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8D54E1F7566A817BB3B988AC /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@ -410,6 +526,7 @@
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9702D4B740EAB4624B982FE0 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@ -447,6 +564,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -504,6 +622,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -540,7 +659,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = R28MH57GSC;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -549,6 +671,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = dth.innodesi.pingpongapp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@ -562,7 +685,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = R28MH57GSC;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -571,6 +697,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = dth.innodesi.pingpongapp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";

View file

@ -4,4 +4,7 @@
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View file

@ -1,7 +1,7 @@
import Flutter
import UIKit
@UIApplicationMain
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,

3
lib/globals.dart Normal file
View file

@ -0,0 +1,3 @@
// lib/globals.dart
const String apiurl = "https://api.dthpp.mercurio.moe";
//const String apiurl = "http://192.168.1.120:9134";

View file

@ -17,7 +17,7 @@ class MyApp extends StatelessWidget {
title: 'Ping Pong Tracker',
theme: ThemeData.dark(useMaterial3: true).copyWith(
colorScheme: ColorScheme.dark(
primary: Colors.blue.shade900,
primary: Colors.blue.shade800,
),
),
home: EntryPoint(),

View file

@ -7,6 +7,9 @@ import 'views/joinmatch.dart';
import 'views/creatematch.dart';
import 'views/friendlist.dart';
import 'views/myprofile.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import '../globals.dart';
class HomePage extends StatefulWidget {
@override
@ -16,7 +19,6 @@ class HomePage extends StatefulWidget {
class _HomePageState extends State<HomePage> {
int _selectedIndex = 0;
// Define the pages for each section
final List<Widget> _pages = [
LeaderboardPage(),
JoinMatchPage(),
@ -40,12 +42,70 @@ class _HomePageState extends State<HomePage> {
);
}
Future<Map<String, String>> fetchCommitHashes() async {
const apiUrl = '$apiurl/version';
try {
final response = await http.get(Uri.parse(apiUrl));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
String formatHash(String? hash) {
if (hash == null) return 'Unknown';
return '#${hash.substring(0, 8).toUpperCase()}';
}
return {
'backend': formatHash(data['backend']),
'frontend': formatHash(data['frontend']),
};
} else {
throw Exception('Failed to fetch commit hashes');
}
} catch (e) {
return {
'backend': 'Error fetching hash',
'frontend': 'Error fetching hash',
};
}
}
Future<void> _showOpenSourceLicenses() async {
final commitHashes = await fetchCommitHashes();
showDialog(
context: context,
builder: (BuildContext context) => AboutDialog(
applicationIcon: const Icon(Icons.code),
applicationLegalese: '© 2024 Thomas Bassi @ Defence Tech.',
applicationName: 'DTHPP',
applicationVersion:
'API: ${commitHashes['backend']} - UI: ${commitHashes['frontend']}',
children: [
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Text(
"Do people even care about licenses? Is this ever going to be opened? Anywho, i hope you're enjoying the app and having fun on your break :D",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Ping Pong Tracker'),
actions: [
IconButton(
icon: Icon(Icons.info),
onPressed: _showOpenSourceLicenses,
tooltip: 'Open Source Licenses',
),
IconButton(
icon: Icon(Icons.logout),
onPressed: () => _logout(context),

View file

@ -3,7 +3,9 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'home.dart';
import '../globals.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:url_launcher/url_launcher.dart';
class LoginPage extends StatefulWidget {
@override
@ -18,11 +20,20 @@ class _LoginPageState extends State<LoginPage> {
bool _isLogin = true;
bool _isLoading = false;
final String baseUrl = 'http://api.dthpp.mercurio.moe';
Future<void> _handleAuth() async {
final email = _emailController.text.trim();
final password = _passwordController.text.trim();
final displayName = _displayNameController.text.trim();
// Input validation
if (email.isEmpty ||
password.isEmpty ||
(!_isLogin && displayName.isEmpty)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Please fill in all required fields.')),
);
return;
}
setState(() {
_isLoading = true;
@ -38,13 +49,13 @@ class _LoginPageState extends State<LoginPage> {
context, MaterialPageRoute(builder: (context) => HomePage()));
}
} else {
final uid = await _register(email, password, _displayNameController.text.trim());
final uid = await _register(email, password, displayName);
if (uid != null) {
setState(() {
_isLogin = true;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Registration successful! Please login.')));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Registration successful! Please login.')));
}
}
} catch (e) {
@ -58,7 +69,7 @@ class _LoginPageState extends State<LoginPage> {
}
Future<String?> _login(String email, String password) async {
final url = Uri.parse('$baseUrl/login');
final url = Uri.parse('$apiurl/login');
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
@ -73,8 +84,9 @@ class _LoginPageState extends State<LoginPage> {
}
}
Future<String?> _register(String email, String password, String displayName) async {
final url = Uri.parse('$baseUrl/register');
Future<String?> _register(
String email, String password, String displayName) async {
final url = Uri.parse('$apiurl/register');
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
@ -118,21 +130,61 @@ class _LoginPageState extends State<LoginPage> {
decoration: InputDecoration(labelText: 'Display Name'),
),
const SizedBox(height: 20),
_isLoading
? CircularProgressIndicator()
: ElevatedButton(
if (_isLoading)
CircularProgressIndicator()
else
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _handleAuth,
child: Text(_isLogin ? 'Login' : 'Register'),
),
TextButton(
ElevatedButton(
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
child: Text(_isLogin
? 'Don\'t have an account? Register'
: 'Already have an account? Login'),
child: Text(_isLogin ? 'Register' : 'Back to Login'),
),
],
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: Icon(FontAwesomeIcons.github),
onPressed: () async {
final url = Uri.parse(
'https://git.mercurio.moe/Mercury/dth-pingpong-mobileapp');
if (await canLaunchUrl(url)) {
await launchUrl(
url,
mode: LaunchMode
.externalApplication, // Ensures it opens in the browser
);
} else {
throw 'Could not launch $url';
}
}),
IconButton(
icon: Icon(FontAwesomeIcons.chartSimple),
onPressed: () async {
final url =
Uri.parse('https://kuma.mercurio.moe/status/dthpp');
if (await canLaunchUrl(url)) {
await launchUrl(
url,
mode: LaunchMode
.externalApplication, // Ensures it opens in the browser
);
} else {
throw 'Could not launch $url';
}
}),
],
),
],
),

View file

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import '../../globals.dart';
class CreateMatchPage extends StatefulWidget {
@override
@ -12,9 +13,8 @@ class _CreateMatchPageState extends State<CreateMatchPage> {
String? _matchId;
bool _isLoading = false;
final String _createMatchApiUrl = 'http://api.dthpp.mercurio.moe/creatematch'; // Replace with your API endpoint
final String _createMatchApiUrl = '$apiurl/creatematch';
// Method to create a match
Future<void> _createMatch() async {
setState(() {
_isLoading = true;
@ -88,6 +88,12 @@ class _CreateMatchPageState extends State<CreateMatchPage> {
textAlign: TextAlign.center,
),
SizedBox(height: 16),
Text(
'Due to current limitations in how we handle matchmaking, only the joining player can control the match. This is only a temporary solution to a problem we are actively fixing.',
style: TextStyle(fontSize: 14),
textAlign: TextAlign.center,
),
SizedBox(height: 16),
_isLoading
? CircularProgressIndicator() // Show loading spinner
: ElevatedButton(

View file

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import '../../globals.dart';
class AddFriendPage extends StatefulWidget {
@override
@ -13,8 +14,8 @@ class _AddFriendPageState extends State<AddFriendPage> {
List<dynamic> _friends = [];
bool _isLoading = false;
final String _addFriendApiUrl = 'http://api.dthpp.mercurio.moe/add_friend';
final String _getFriendsApiUrl = 'http://api.dthpp.mercurio.moe/get_friends';
final String _addFriendApiUrl = '$apiurl/add_friend';
final String _getFriendsApiUrl = '$apiurl/get_friends';
// Method to add a friend
Future<void> _addFriend(String friendUid) async {

View file

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import '../../globals.dart';
class JoinMatchPage extends StatefulWidget {
@override
@ -16,10 +17,9 @@ class _JoinMatchPageState extends State<JoinMatchPage> {
int _player2Score = 0;
String? _matchId;
final String _joinMatchApiUrl = 'http://api.dthpp.mercurio.moe/joinmatch'; // Replace with your API endpoint
final String _endMatchApiUrl = 'http://api.dthpp.mercurio.moe/endmatch'; // Replace with your API endpoint
final String _joinMatchApiUrl = '$apiurl/joinmatch';
final String _endMatchApiUrl = '$apiurl/endmatch';
// Join Match Function
Future<void> _joinMatch() async {
setState(() {
_isLoading = true;
@ -64,7 +64,6 @@ class _JoinMatchPageState extends State<JoinMatchPage> {
}
}
// Increment/Decrement Player Scores
void _updateScore(int player, int delta) {
setState(() {
if (player == 1) {
@ -75,7 +74,6 @@ class _JoinMatchPageState extends State<JoinMatchPage> {
});
}
// End Match Function
Future<void> _endMatch() async {
setState(() {
_isLoading = true;

View file

@ -1,6 +1,7 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../../globals.dart';
class LeaderboardPage extends StatefulWidget {
@override
@ -11,7 +12,7 @@ class _LeaderboardPageState extends State<LeaderboardPage> {
List<dynamic> _leaderboard = [];
bool _isLoading = true;
final String _apiUrl = 'http://api.dthpp.mercurio.moe/leaderboards';
final String _leaderboardApi = '$apiurl/leaderboards';
Future<void> _fetchLeaderboard() async {
setState(() {
@ -19,7 +20,7 @@ class _LeaderboardPageState extends State<LeaderboardPage> {
});
try {
final response = await http.get(Uri.parse(_apiUrl));
final response = await http.get(Uri.parse(_leaderboardApi));
if (response.statusCode == 200) {
List<dynamic> data = json.decode(response.body);

View file

@ -3,6 +3,7 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import '../../globals.dart';
class ProfilePage extends StatefulWidget {
@override
@ -16,7 +17,7 @@ class _ProfilePageState extends State<ProfilePage> {
int? _elo;
List<dynamic> _matches = [];
final String _getProfileApiUrl = 'http://api.dthpp.mercurio.moe/getprofile';
final String _getProfileApiUrl = '$apiurl/getprofile';
@override
void initState() {
@ -144,7 +145,8 @@ class _ProfilePageState extends State<ProfilePage> {
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'Match ID: ${match['match_id']}',
@ -153,7 +155,8 @@ class _ProfilePageState extends State<ProfilePage> {
fontWeight: FontWeight.bold,
),
),
Text('Opponent: ${match['opponent_name']}'),
Text(
'Opponent: ${match['opponent_name']}'),
Row(
children: [
Text(

View file

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -5,8 +5,10 @@
import FlutterMacOS
import Foundation
import package_info
import shared_preferences_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}

43
macos/Podfile Normal file
View file

@ -0,0 +1,43 @@
platform :osx, '10.14'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_macos_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_macos_build_settings(target)
end
end

View file

@ -1,8 +1,8 @@
name: pingpongapp
description: "A new Flutter project."
description: "DTH Ping Pong Score tracking app"
publish_to: 'none'
version: 0.0.32+1
version: 0.0.34+1
environment:
sdk: '>=3.4.3 <4.0.0'
@ -14,6 +14,9 @@ dependencies:
shared_preferences: ^2.3.3
http: ^1.2.2
logger: ^2.5.0
package_info: ^2.0.2
font_awesome_flutter: ^10.8.0
url_launcher: ^6.3.1
dev_dependencies:
flutter_test: