Skip to content
Merged
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
7 changes: 6 additions & 1 deletion .github/workflows/ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ jobs:
")
echo "Found simulator: $simulator_id"
echo "SIMULATOR_ID=$simulator_id" >> $GITHUB_ENV
- name: Boot Simulator
# Boot the simulator up front so the first UI-test launch doesn't race the cold boot and hit Xcode's launch timeout.
run: |
xcrun simctl boot "$SIMULATOR_ID"
xcrun simctl bootstatus "$SIMULATOR_ID" -b
- name: Build
env:
scheme: ${{ 'default' }}
Expand All @@ -58,4 +63,4 @@ jobs:
if [ $scheme = default ]; then scheme=$(cat default); fi
if [ "`ls -A | grep -i \\.xcworkspace\$`" ]; then filetype_parameter="workspace" && file_to_build="`ls -A | grep -i \\.xcworkspace\$`"; else filetype_parameter="project" && file_to_build="`ls -A | grep -i \\.xcodeproj\$`"; fi
file_to_build=`echo $file_to_build | awk '{$1=$1;print}'`
xcodebuild test-without-building -scheme "$scheme" -"$filetype_parameter" "$file_to_build" -destination "platform=iOS Simulator,id=$SIMULATOR_ID"
xcodebuild test-without-building -scheme "$scheme" -"$filetype_parameter" "$file_to_build" -destination "platform=iOS Simulator,id=$SIMULATOR_ID" -retry-tests-on-failure -test-iterations 2
12 changes: 4 additions & 8 deletions PayForMe.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
6524D60225385E0800B2AA7B /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 6524D60125385E0800B2AA7B /* GRDB */; };
6533A02B23D888B100FF822B /* BillCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6533A02A23D888B100FF822B /* BillCell.swift */; };
654754B82528736F00A82EB6 /* Views+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654754B72528736F00A82EB6 /* Views+Extensions.swift */; };
654754BC2528750A00A82EB6 /* FloatingAddButtonViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654754BB2528750A00A82EB6 /* FloatingAddButtonViewModifier.swift */; };
654754C0252889B200A82EB6 /* ProjectQRPermissionCheckerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654754BF252889B200A82EB6 /* ProjectQRPermissionCheckerView.swift */; };
654754C8252899FF00A82EB6 /* FancyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654754C7252899FF00A82EB6 /* FancyButton.swift */; };
654754E42528B29F00A82EB6 /* AddProjectManuallyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654754E32528B29F00A82EB6 /* AddProjectManuallyTests.swift */; };
Expand Down Expand Up @@ -111,7 +110,6 @@
6523FC502558153600BCD843 /* AddPasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddPasswordView.swift; sourceTree = "<group>"; };
6533A02A23D888B100FF822B /* BillCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BillCell.swift; sourceTree = "<group>"; };
654754B72528736F00A82EB6 /* Views+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Views+Extensions.swift"; sourceTree = "<group>"; };
654754BB2528750A00A82EB6 /* FloatingAddButtonViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingAddButtonViewModifier.swift; sourceTree = "<group>"; };
654754BF252889B200A82EB6 /* ProjectQRPermissionCheckerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectQRPermissionCheckerView.swift; sourceTree = "<group>"; };
654754C7252899FF00A82EB6 /* FancyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FancyButton.swift; sourceTree = "<group>"; };
654754E12528B29F00A82EB6 /* PayForMeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PayForMeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -379,7 +377,6 @@
489D35F923E081120029F59F /* Util.swift */,
65A65E3E2527529D00C86533 /* Combine.swift */,
654754B72528736F00A82EB6 /* Views+Extensions.swift */,
654754BB2528750A00A82EB6 /* FloatingAddButtonViewModifier.swift */,
);
path = Util;
sourceTree = "<group>";
Expand Down Expand Up @@ -575,7 +572,6 @@
650059FC23DDE1C300D1D599 /* Person.swift in Sources */,
65662A0323D7320000303207 /* AppDelegate.swift in Sources */,
654754C0252889B200A82EB6 /* ProjectQRPermissionCheckerView.swift in Sources */,
654754BC2528750A00A82EB6 /* FloatingAddButtonViewModifier.swift in Sources */,
6533A02B23D888B100FF822B /* BillCell.swift in Sources */,
48CF709B240FF82000770B97 /* AddMemberView.swift in Sources */,
65D9094025581BE100351F4B /* AddFromURLView.swift in Sources */,
Expand Down Expand Up @@ -825,7 +821,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = PayForMe/PayForMe.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 109;
CURRENT_PROJECT_VERSION = 110;
DEVELOPMENT_ASSET_PATHS = "\"PayForMe/Preview Content\"";
DEVELOPMENT_TEAM = 22BT3L9N5V;
ENABLE_PREVIEWS = YES;
Expand All @@ -836,7 +832,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.5.1;
MARKETING_VERSION = 2.6.0;
PRODUCT_BUNDLE_IDENTIFIER = de.mayflower.PayForMe;
PRODUCT_NAME = PayForMe;
SWIFT_VERSION = 5.0;
Expand All @@ -850,7 +846,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = PayForMe/PayForMe.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 109;
CURRENT_PROJECT_VERSION = 110;
DEVELOPMENT_ASSET_PATHS = "\"PayForMe/Preview Content\"";
DEVELOPMENT_TEAM = 22BT3L9N5V;
ENABLE_PREVIEWS = YES;
Expand All @@ -861,7 +857,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.5.1;
MARKETING_VERSION = 2.6.0;
PRODUCT_BUNDLE_IDENTIFIER = de.mayflower.PayForMe;
PRODUCT_NAME = PayForMe;
SWIFT_VERSION = 5.0;
Expand Down
10 changes: 10 additions & 0 deletions PayForMe/Services/NetworkService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,16 @@ class NetworkService {
return sendMemberPublisher(request: request)
}

/// Like `createMemberPublisher`, but returns the HTTP status code (-1 on transport error) so the
/// UI can surface a real error instead of a silent `false`.
func createMemberStatusPublisher(name: String) -> AnyPublisher<Int, Never> {
let request = buildURLRequest("members", params: ["name": name], project: currentProject, httpMethod: "POST")
return URLSession.shared.dataTaskPublisher(for: request)
.map { output -> Int in (output.response as? HTTPURLResponse)?.statusCode ?? -1 }
.replaceError(with: -1)
.eraseToAnyPublisher()
}

func updateMemberPublisher(member: Person) -> AnyPublisher<Bool, Never> {
let request = buildURLRequest("members/\(member.id)", params: ["name": member.name], project: currentProject, httpMethod: "PUT")
return sendMemberPublisher(request: request)
Expand Down
30 changes: 22 additions & 8 deletions PayForMe/Services/ProjectManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,19 @@ enum StoringError: Error {

extension ProjectManager {
func addProject(_ project: Project) throws {
guard storageService.saveProject(project: project) else {
let didSave = storageService.saveProject(project: project)
let reloaded = storageService.loadProjects()

// An already-existing project is not an error: it just gets activated (same for manual add
// and QR scan). Only a real save failure throws.
guard didSave || reloaded.contains(project) else {
throw StoringError.couldNotSave
}
DispatchQueue.main.async { [self] in
projects = storageService.loadProjects()
projects = reloaded

if projects.count == 1 {
setCurrentProject(project)
}
// Always activate the added (or already-known) project, whether it's the first or not.
setCurrentProject(project)
openedByURL = nil
print("project added")
}
Expand Down Expand Up @@ -240,9 +244,19 @@ extension ProjectManager {
deleteBillFromServer(bill: bill, completion: completion)
}

func addMember(_ name: String, completion: @escaping () -> Void) {
let newMember = Person(id: -1, weight: -1, name: name, activated: true, color: nil)
sendMemberToServer(newMember, update: false, completion: completion)
/// Creates a member and reports the HTTP status code (2xx = success, -1 = transport error) so the UI can surface a real error.
func addMember(_ name: String, completion: @escaping (Int) -> Void) {
cancellable?.cancel()
cancellable = NetworkService.shared.createMemberStatusPublisher(name: name)
.receive(on: DispatchQueue.main)
.sink { statusCode in
if (200 ... 299).contains(statusCode) {
print("Member successfully created")
} else {
print("Error creating member: HTTP \(statusCode)")
}
completion(statusCode)
}
}

func updateMember(_ member: Person, completion: @escaping () -> Void) {
Expand Down
15 changes: 13 additions & 2 deletions PayForMe/Strings/cs.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"Enter project id" = "Zadejte identifikátor projektu";


"Enter project password" = "Zadejte heslo k projektu";
"Enter project password (Optional)" = "Zadejte heslo k projektu (volitelné)";

/* */
"Expense date" = "Datum výdaje";
Expand Down Expand Up @@ -117,7 +117,7 @@
"Sure" = "Jistě";


"To get started sharing expenses with friends, you must add a project from Cospend or iHateMoney. \n\n Cospend projects can be added by QR Code or by manually filling out the information, for iHateMoney you need to fill out the information manually." = "Pokud chcete začít sdílet náklady s přáteli, je třeba přidat projekt z Cospend nebo iHateMoney. \n\n Cospend projekty je možné přidávat prostřednictvím QR kódu nebo ručně vyplněním potřebných údajů, pro iHateMoney je třeba vyplnit potřebné údaje vždy ručně.";
"To get started sharing expenses with friends, you must add a project from Cospend or iHateMoney. To do this, scan the QR code or click the link for the project that was shared with you." = "Chcete-li začít sdílet výdaje s přáteli, musíte přidat projekt z Cospend nebo iHateMoney. Naskenujte k tomu QR kód nebo klikněte na odkaz projektu, který vám byl sdílen.";


"To use iHateMoney, host an own instance or register at" = "Pokud chcete použít iHateMoney, hostujte si svou vlastní instanci nebo se zaregistrujte na";
Expand All @@ -139,3 +139,14 @@


"What was paid" = "Co bylo placeno?";

/* Feedback round 2.6.0 */
"Cancel" = "Zrušit";
"Scan QR code" = "Naskenovat QR kód";
"Backend" = "Backend";
"server_hint_cospend" = "Váš vlastní server Cospend (Nextcloud).";
"server_hint_ihatemoney" = "Ponechte prázdné pro oficiální instanci, nebo zadejte vlastní instanci.";
"Could not add member" = "Člena se nepodařilo přidat";
"member_error_forbidden" = "To obvykle vyžaduje práva správce projektu. Sdílené heslo projektu může umožňovat jen přístup účastníka.";
"member_error_network" = "Není spojení se serverem. Zkontrolujte síť a zkuste to znovu.";
"member_error_generic" = "Server odmítl požadavek (HTTP %d).";
21 changes: 18 additions & 3 deletions PayForMe/Strings/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"Enter project id" = "Projekt ID eingeben";


"Enter project password" = "Projekt Passwort eingeben";
"Enter project password (Optional)" = "Projekt Passwort eingeben (optional)";

/* */
"Expense date" = "Datum der Aufwendung";
Expand Down Expand Up @@ -86,6 +86,10 @@

"Paste Link" = "Link einsetzen";

"Invite Link" = "Invite-Link";
"Enter invite link" = "Invite-Link einsetzen";
"invite_link_hint" = "Kompletten Invite-Link einsetzen. Server und Projekt werden automatisch erkannt.";


"Payer" = "Zahler";

Expand Down Expand Up @@ -114,10 +118,10 @@
"Sure" = "Sicher";


"To get started sharing expenses with friends, you must add a project from Cospend or iHateMoney. \n\n Cospend projects can be added by QR Code or by manually filling out the information, for iHateMoney you need to fill out the information manually." = "Um deine Ausgaben mit Freunden teilen zu können, musst du ein Projekt von Cospend oder iHateMoney hinzufügen \n\n Cospend Projekte können manuell oder mit QR-Code hinzugefügt werden, für iHateMoney musst du das Projekt manuell hinzufügen.";
"To get started sharing expenses with friends, you must add a project from Cospend or iHateMoney. To do this, scan the QR code or click the link for the project that was shared with you." = "Um deine Ausgaben mit Freunden teilen zu können, musst du ein Projekt von Cospend oder iHateMoney hinzufügen. Scanne dazu den QR-Code oder klicke den Link des Projekts, der dir geteilt wurde.";


"To use iHateMoney, host an own instance or register at" = "Um iHateMoney zu benutzen, hoste eine eigene Instanz oder registrier dich bei";
"To use iHateMoney, host an own instance or register at" = "Um iHateMoney zu benutzen, hoste eine eigene Instanz oder registriere dich bei";


"Type password here" = "Hier Passwort eingeben";
Expand All @@ -139,3 +143,14 @@


"Server returned an invalid HTTP response" = "Server lieferte eine ungültige HTTP-Antwort";

/* Feedback round 2.6.0 */
"Cancel" = "Abbrechen";
"Scan QR code" = "QR-Code scannen";
"Backend" = "Backend";
"server_hint_cospend" = "Dein selbstgehosteter Cospend-Server (Nextcloud).";
"server_hint_ihatemoney" = "Leer lassen für die offizielle Instanz oder eigene Domain eintragen.";
"Could not add member" = "Mitglied hinzugefügt gescheitert";
"member_error_forbidden" = "Für den Erfolg sind meist Maintainer-Rechte am Projekt nötig. Du kannst diese Berechtigungen jederzeit erteilen, indem du die Einstellungen des Freigabelinks in Cospend (deiner Nextcloud-App) änderst.";
"member_error_network" = "Keine Verbindung zum Server. Bitte Netzwerk prüfen und erneut versuchen.";
"member_error_generic" = "Der Server hat die Anfrage abgelehnt (HTTP %d).";
19 changes: 17 additions & 2 deletions PayForMe/Strings/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"Enter project id" = "Enter project id";


"Enter project password" = "Enter project password";
"Enter project password (Optional)" = "Enter project password (Optional)";


"Expense date" = "Expense date";
Expand Down Expand Up @@ -89,6 +89,10 @@

"Paste Link" = "Paste Link";

"Invite Link" = "Invite Link";
"Enter invite link" = "Enter invite link";
"invite_link_hint" = "Paste the full invite link. Server and project are detected automatically.";

/* BillDetail.swift */
"Payer" = "Payer";

Expand Down Expand Up @@ -117,7 +121,7 @@
"Sure" = "Sure";


"To get started sharing expenses with friends, you must add a project from Cospend or iHateMoney. \n\n Cospend projects can be added by QR Code or by manually filling out the information, for iHateMoney you need to fill out the information manually." = "To get started sharing expenses with friends, you must add a project from Cospend or iHateMoney. \n\n Cospend projects can be added by QR Code or by manually filling out the information, for iHateMoney you need to fill out the information manually.";
"To get started sharing expenses with friends, you must add a project from Cospend or iHateMoney. To do this, scan the QR code or click the link for the project that was shared with you." = "To get started sharing expenses with friends, you must add a project from Cospend or iHateMoney. To do this, scan the QR code or click the link for the project that was shared with you.";


"To use iHateMoney, host an own instance or register at" = "To use iHateMoney, host an own instance or register at";
Expand All @@ -142,3 +146,14 @@


"Server returned an invalid HTTP response" = "Server returned an invalid HTTP response";

/* Feedback round 2.6.0 */
"Cancel" = "Cancel";
"Scan QR code" = "Scan QR code";
"Backend" = "Backend";
"server_hint_cospend" = "Your self-hosted Cospend (Nextcloud) server.";
"server_hint_ihatemoney" = "Leave empty for the official instance, or enter your own domain.";
"Could not add member" = "Could not add member";
"member_error_forbidden" = "This usually requires maintainer rights for the project. You can grant those at any time by changing the share-link's settings in Cospend (your Nextcloud-App).";
"member_error_network" = "No connection to the server. Please check your network and try again.";
"member_error_generic" = "The server rejected the request (HTTP %d).";
15 changes: 13 additions & 2 deletions PayForMe/Strings/es.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"Enter project id" = "Entrar el ID del proyecto";


"Enter project password" = "Entrar la contraseña del proyecto";
"Enter project password (Optional)" = "Entrar la contraseña del proyecto (opcional)";

/* */
"Expense date" = "Fecha de gasto";
Expand Down Expand Up @@ -120,7 +120,7 @@
"Sure" = "Claro";

/* */
"To get started sharing expenses with friends, you must add a project from Cospend or iHateMoney. \n\n Cospend projects can be added by QR Code or by manually filling out the information, for iHateMoney you need to fill out the information manually." = "Para empezar a compartir gastos con amigos, debes añadir un proyecto de Cospend o iHateMoney. \Los proyectos de Cospend se pueden añadir mediante un código QR o rellenando manualmente la información, para iHateMoney es necesario rellenar la información manualmente.";
"To get started sharing expenses with friends, you must add a project from Cospend or iHateMoney. To do this, scan the QR code or click the link for the project that was shared with you." = "Para empezar a compartir gastos con amigos, debes añadir un proyecto de Cospend o iHateMoney. Para ello, escanea el código QR o haz clic en el enlace del proyecto que te han compartido.";

/* */
"To use iHateMoney, host an own instance or register at" = "Para utilizar iHateMoney, aloje una instancia propia o regístrese en";
Expand All @@ -142,3 +142,14 @@


"What was paid" = "¿Qué se pagó?";

/* Feedback round 2.6.0 */
"Cancel" = "Cancelar";
"Scan QR code" = "Escanear código QR";
"Backend" = "Backend";
"server_hint_cospend" = "Tu servidor Cospend autoalojado (Nextcloud).";
"server_hint_ihatemoney" = "Déjalo vacío para la instancia oficial, o introduce tu instancia.";
"Could not add member" = "No se pudo añadir el miembro";
"member_error_forbidden" = "Esto suele requerir permisos de mantenedor del proyecto. La contraseña compartida puede dar solo acceso de participante.";
"member_error_network" = "Sin conexión con el servidor. Comprueba tu red e inténtalo de nuevo.";
"member_error_generic" = "El servidor rechazó la solicitud (HTTP %d).";
Loading
Loading