diff --git a/BUILDING.md b/BUILDING.md index 1dd322e0..0928cf66 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1151,28 +1151,28 @@ If you need to build manually or want to understand the individual steps: - ... and you may have to fix these, especially with pkgx: - ```bash - gem_path=$(which gem) - shortened_path="${gem_path:h:h}" - export GEM_HOME=$shortened_path - export GEM_PATH=$shortened_path - ``` +```bash +gem_path=$(which gem) +shortened_path="${gem_path:h:h}" +export GEM_HOME=$shortened_path +export GEM_PATH=$shortened_path +``` ##### 1. Bump the version in package.json for `MARKETING_VERSION`, then `grep CURRENT_PROJECT_VERSION ios/App/App.xcodeproj/project.pbxproj` and add 1 for the numbered version; - ```bash - cd ios/App && xcrun agvtool new-version 46 && perl -p -i -e "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 1.1.1;/g" App.xcodeproj/project.pbxproj && cd - - # Unfortunately this edits Info.plist directly. - #xcrun agvtool new-marketing-version 0.4.5 - ``` +```bash +cd ios/App && xcrun agvtool new-version 47 && perl -p -i -e "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 1.1.2;/g" App.xcodeproj/project.pbxproj && cd - +# Unfortunately this edits Info.plist directly. +#xcrun agvtool new-marketing-version 0.4.5 +``` ##### 2. Build - Here's prod. Also available: test, dev +Here's prod. Also available: test, dev - ```bash - npm run build:ios:prod - ``` +```bash +npm run build:ios:prod +``` 3.1. Use Xcode to build and run on simulator or device. @@ -1197,7 +1197,8 @@ If you need to build manually or want to understand the individual steps: - It can take 15 minutes for the build to show up in the list of builds. - You'll probably have to "Manage" something about encryption, disallowed in France. - Then "Save" and "Add to Review" and "Resubmit to App Review". -- Eventually it'll be "Ready for Distribution" which means +- Eventually it'll be "Ready for Distribution" which means it's live +- When finished, bump package.json version ### Android Build @@ -1315,26 +1316,26 @@ The recommended way to build for Android is using the automated build script: #### Android Manual Build Process -##### 1. Bump the version in package.json, then here: android/app/build.gradle +##### 1. Bump the version in package.json, then update these versions & run: - ```bash - perl -p -i -e 's/versionCode .*/versionCode 46/g' android/app/build.gradle - perl -p -i -e 's/versionName .*/versionName "1.1.1"/g' android/app/build.gradle - ``` +```bash +perl -p -i -e 's/versionCode .*/versionCode 47/g' android/app/build.gradle +perl -p -i -e 's/versionName .*/versionName "1.1.2"/g' android/app/build.gradle +``` ##### 2. Build Here's prod. Also available: test, dev - ```bash - npm run build:android:prod - ``` +```bash +npm run build:android:prod +``` ##### 3. Open the project in Android Studio - ```bash - npx cap open android - ``` +```bash +npx cap open android +``` ##### 4. Use Android Studio to build and run on emulator or device @@ -1379,6 +1380,8 @@ At play.google.com/console: - Note that if you add testers, you have to go to "Publishing Overview" and send those changes or your (closed) testers won't see it. +- When finished, bump package.json version + ### Capacitor Operations ```bash diff --git a/CHANGELOG.md b/CHANGELOG.md index ff6bd9b8..b59c254c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.2] - 2025.11.06 + +### Fixed +- Bad page when user follows prompt to backup seed + + ## [1.1.1] - 2025.11.03 ### Added diff --git a/android/app/build.gradle b/android/app/build.gradle index d37bbd98..edd4acd1 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -31,8 +31,8 @@ android { applicationId "app.timesafari.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 46 - versionName "1.1.1" + versionCode 47 + versionName "1.1.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index c68a3087..fa09b22c 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -403,7 +403,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 46; + CURRENT_PROJECT_VERSION = 47; DEVELOPMENT_TEAM = GM3FS5JQPH; ENABLE_APP_SANDBOX = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO; @@ -413,7 +413,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.2; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = app.timesafari; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -430,7 +430,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 46; + CURRENT_PROJECT_VERSION = 47; DEVELOPMENT_TEAM = GM3FS5JQPH; ENABLE_APP_SANDBOX = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO; @@ -440,7 +440,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.2; PRODUCT_BUNDLE_IDENTIFIER = app.timesafari; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; diff --git a/package-lock.json b/package-lock.json index 1ca0e8a5..93b98785 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "timesafari", - "version": "1.1.2-beta", + "version": "1.1.3-beta", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "timesafari", - "version": "1.1.2-beta", + "version": "1.1.3-beta", "dependencies": { "@capacitor-community/electron": "^5.0.1", "@capacitor-community/sqlite": "6.0.2", diff --git a/package.json b/package.json index 1956ef2a..6a02f4fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "timesafari", - "version": "1.1.2-beta", + "version": "1.1.3-beta", "description": "Time Safari Application", "author": { "name": "Time Safari Team" diff --git a/scripts/build-android.sh b/scripts/build-android.sh index b8c4669a..39383064 100755 --- a/scripts/build-android.sh +++ b/scripts/build-android.sh @@ -436,7 +436,21 @@ fi log_info "Cleaning dist directory..." clean_build_artifacts "dist" -# Step 4: Build Capacitor version with mode +# Step 4: Run TypeScript type checking for test and production builds +if [ "$BUILD_MODE" = "production" ] || [ "$BUILD_MODE" = "test" ]; then + log_info "Running TypeScript type checking for $BUILD_MODE mode..." + + if ! measure_time npm run type-check; then + log_error "TypeScript type checking failed for $BUILD_MODE mode!" + exit 2 + fi + + log_success "TypeScript type checking completed for $BUILD_MODE mode" +else + log_debug "Skipping TypeScript type checking for development mode" +fi + +# Step 5: Build Capacitor version with mode if [ "$BUILD_MODE" = "development" ]; then safe_execute "Building Capacitor version (development)" "npm run build:capacitor" || exit 3 elif [ "$BUILD_MODE" = "test" ]; then @@ -445,23 +459,23 @@ elif [ "$BUILD_MODE" = "production" ]; then safe_execute "Building Capacitor version (production)" "npm run build:capacitor -- --mode production" || exit 3 fi -# Step 5: Clean Gradle build +# Step 6: Clean Gradle build safe_execute "Cleaning Gradle build" "cd android && ./gradlew clean && cd .." || exit 4 -# Step 6: Build based on type +# Step 7: Build based on type if [ "$BUILD_TYPE" = "debug" ]; then safe_execute "Assembling debug build" "cd android && ./gradlew assembleDebug && cd .." || exit 5 elif [ "$BUILD_TYPE" = "release" ]; then safe_execute "Assembling release build" "cd android && ./gradlew assembleRelease && cd .." || exit 5 fi -# Step 7: Sync with Capacitor +# Step 8: Sync with Capacitor safe_execute "Syncing with Capacitor" "npx cap sync android" || exit 6 -# Step 8: Generate assets +# Step 9: Generate assets safe_execute "Generating assets" "npx capacitor-assets generate --android" || exit 7 -# Step 9: Build APK/AAB if requested +# Step 10: Build APK/AAB if requested if [ "$BUILD_APK" = true ]; then if [ "$BUILD_TYPE" = "debug" ]; then safe_execute "Building debug APK" "cd android && ./gradlew assembleDebug && cd .." || exit 5 @@ -474,7 +488,7 @@ if [ "$BUILD_AAB" = true ]; then safe_execute "Building AAB" "cd android && ./gradlew bundleRelease && cd .." || exit 5 fi -# Step 10: Auto-run app if requested +# Step 11: Auto-run app if requested if [ "$AUTO_RUN" = true ]; then log_step "Auto-running Android app..." safe_execute "Launching app" "npx cap run android" || { @@ -485,7 +499,7 @@ if [ "$AUTO_RUN" = true ]; then log_success "Android app launched successfully!" fi -# Step 11: Open Android Studio if requested +# Step 12: Open Android Studio if requested if [ "$OPEN_STUDIO" = true ]; then safe_execute "Opening Android Studio" "npx cap open android" || exit 8 fi diff --git a/scripts/build-ios.sh b/scripts/build-ios.sh index fd4e9a39..b327152c 100755 --- a/scripts/build-ios.sh +++ b/scripts/build-ios.sh @@ -381,7 +381,21 @@ safe_execute "Cleaning iOS build" "clean_ios_build" || exit 1 log_info "Cleaning dist directory..." clean_build_artifacts "dist" -# Step 4: Build Capacitor version with mode +# Step 4: Run TypeScript type checking for test and production builds +if [ "$BUILD_MODE" = "production" ] || [ "$BUILD_MODE" = "test" ]; then + log_info "Running TypeScript type checking for $BUILD_MODE mode..." + + if ! measure_time npm run type-check; then + log_error "TypeScript type checking failed for $BUILD_MODE mode!" + exit 2 + fi + + log_success "TypeScript type checking completed for $BUILD_MODE mode" +else + log_debug "Skipping TypeScript type checking for development mode" +fi + +# Step 5: Build Capacitor version with mode if [ "$BUILD_MODE" = "development" ]; then safe_execute "Building Capacitor version (development)" "npm run build:capacitor" || exit 3 elif [ "$BUILD_MODE" = "test" ]; then @@ -390,16 +404,16 @@ elif [ "$BUILD_MODE" = "production" ]; then safe_execute "Building Capacitor version (production)" "npm run build:capacitor -- --mode production" || exit 3 fi -# Step 5: Sync with Capacitor +# Step 6: Sync with Capacitor safe_execute "Syncing with Capacitor" "npx cap sync ios" || exit 6 -# Step 6: Generate assets +# Step 7: Generate assets safe_execute "Generating assets" "npx capacitor-assets generate --ios" || exit 7 -# Step 7: Build iOS app +# Step 8: Build iOS app safe_execute "Building iOS app" "build_ios_app" || exit 5 -# Step 8: Build IPA/App if requested +# Step 9: Build IPA/App if requested if [ "$BUILD_IPA" = true ]; then log_info "Building IPA package..." cd ios/App @@ -426,12 +440,12 @@ if [ "$BUILD_APP" = true ]; then log_success "App bundle built successfully" fi -# Step 9: Auto-run app if requested +# Step 10: Auto-run app if requested if [ "$AUTO_RUN" = true ]; then safe_execute "Auto-running iOS app" "auto_run_ios_app" || exit 9 fi -# Step 10: Open Xcode if requested +# Step 11: Open Xcode if requested if [ "$OPEN_STUDIO" = true ]; then safe_execute "Opening Xcode" "npx cap open ios" || exit 8 fi diff --git a/src/assets/styles/tailwind.css b/src/assets/styles/tailwind.css index f4e5b371..085b8ee3 100644 --- a/src/assets/styles/tailwind.css +++ b/src/assets/styles/tailwind.css @@ -38,7 +38,7 @@ } .dialog { - @apply bg-white px-4 py-6 rounded-lg w-full max-w-lg max-h-[90%] overflow-y-auto; + @apply bg-white px-4 py-6 rounded-lg w-full max-w-lg max-h-[calc(100vh-3rem)] overflow-y-auto; } /* Markdown content styling to restore list elements */ diff --git a/src/components/BulkMembersDialog.vue b/src/components/BulkMembersDialog.vue index 412ade19..abce37cc 100644 --- a/src/components/BulkMembersDialog.vue +++ b/src/components/BulkMembersDialog.vue @@ -111,7 +111,7 @@ ? 'bg-blue-600 text-white cursor-pointer' : 'bg-slate-400 text-slate-200 cursor-not-allowed', ]" - @click="handleMainAction" + @click="processSelectedMembers" > {{ buttonText }} @@ -145,7 +145,7 @@ import { Contact } from "@/db/tables/contacts"; export default class BulkMembersDialog extends Vue { @Prop({ default: "" }) activeDid!: string; @Prop({ default: "" }) apiServer!: string; - @Prop({ required: true }) dialogType!: "admit" | "visibility"; + // isOrganizer: true = organizer mode (admit members), false = member mode (set visibility) @Prop({ required: true }) isOrganizer!: boolean; // Vue notification system @@ -252,15 +252,7 @@ export default class BulkMembersDialog extends Vue { return this.selectedMembers.includes(memberDid); } - async handleMainAction() { - if (this.dialogType === "admit") { - await this.organizerAdmitAndAddWithVisibility(); - } else { - await this.memberAddContactWithVisibility(); - } - } - - async organizerAdmitAndAddWithVisibility() { + async processSelectedMembers() { try { const selectedMembers: MemberData[] = this.membersData.filter((member) => this.selectedMembers.includes(member.did), @@ -275,16 +267,20 @@ export default class BulkMembersDialog extends Vue { for (const member of selectedMembers) { try { - // First, admit the member - await this.admitMember(member); - - // Register them - await this.registerMember(member); - admittedCount++; + // Organizer mode: admit and register the member first + if (this.isOrganizer) { + await this.admitMember(member); + await this.registerMember(member); + admittedCount++; + } // If they're not a contact yet, add them as a contact if (!member.isContact) { - await this.addAsContact(member, true); + // Organizer mode: set isRegistered to true, member mode: undefined + await this.addAsContact( + member, + this.isOrganizer ? true : undefined, + ); contactAddedCount++; } @@ -299,88 +295,51 @@ export default class BulkMembersDialog extends Vue { } // Show success notification - if (admittedCount > 0) { - this.$notify( - { - group: "alert", - type: "success", - title: "Members Admitted Successfully", - text: `${admittedCount} member${admittedCount === 1 ? "" : "s"} admitted and registered${contactAddedCount === 0 ? "" : admittedCount === contactAddedCount ? " and" : `, ${contactAddedCount}`}${contactAddedCount === 0 ? "" : ` added as contact${contactAddedCount === 1 ? "" : "s"}`}.`, - }, - 10000, - ); - } - if (errors > 0) { - this.$notify( - { - group: "alert", - type: "danger", - title: "Error", - text: "Failed to fully admit some members. Work with them individually below.", - }, - 5000, - ); - } - - this.close(notSelectedMembers.map((member) => member.did)); - } catch (error) { - // eslint-disable-next-line no-console - console.error("Error admitting members:", error); - this.$notify( - { - group: "alert", - type: "danger", - title: "Error", - text: "Some errors occurred. Work with members individually below.", - }, - 5000, - ); - } - } - - async memberAddContactWithVisibility() { - try { - const selectedMembers: MemberData[] = this.membersData.filter((member) => - this.selectedMembers.includes(member.did), - ); - const notSelectedMembers: MemberData[] = this.membersData.filter( - (member) => !this.selectedMembers.includes(member.did), - ); - - let contactsAddedCount = 0; - - for (const member of selectedMembers) { - try { - // If they're not a contact yet, add them as a contact first - if (!member.isContact) { - await this.addAsContact(member, undefined); - contactsAddedCount++; - } - - // Set their seesMe to true - await this.updateContactVisibility(member.did, true); - } catch (error) { - // eslint-disable-next-line no-console - console.error(`Error processing member ${member.did}:`, error); - // Continue with other members even if one fails + if (this.isOrganizer) { + if (admittedCount > 0) { + this.$notify( + { + group: "alert", + type: "success", + title: "Members Admitted Successfully", + text: `${admittedCount} member${admittedCount === 1 ? "" : "s"} admitted and registered${contactAddedCount === 0 ? "" : admittedCount === contactAddedCount ? " and" : `, ${contactAddedCount}`}${contactAddedCount === 0 ? "" : ` added as contact${contactAddedCount === 1 ? "" : "s"}`}.`, + }, + 5000, + ); + } + if (errors > 0) { + this.$notify( + { + group: "alert", + type: "danger", + title: "Error", + text: "Failed to fully admit some members. Work with them individually below.", + }, + 5000, + ); + } + } else { + // Member mode: show contacts added notification + if (contactAddedCount > 0) { + this.$notify( + { + group: "alert", + type: "success", + title: "Contacts Added Successfully", + text: `${contactAddedCount} member${contactAddedCount === 1 ? "" : "s"} added as contact${contactAddedCount === 1 ? "" : "s"}.`, + }, + 5000, + ); } } - // Show success notification - this.$notify( - { - group: "alert", - type: "success", - title: "Contacts Added Successfully", - text: `${contactsAddedCount} member${contactsAddedCount === 1 ? "" : "s"} added as contact${contactsAddedCount === 1 ? "" : "s"}.`, - }, - 5000, - ); - this.close(notSelectedMembers.map((member) => member.did)); } catch (error) { // eslint-disable-next-line no-console - console.error("Error adding contacts:", error); + console.error( + `Error ${this.isOrganizer ? "admitting members" : "adding contacts"}:`, + error, + ); this.$notify( { group: "alert", @@ -487,10 +446,10 @@ export default class BulkMembersDialog extends Vue { } showContactInfo() { - const message = - this.dialogType === "admit" - ? "This user is already your contact, but they are not yet admitted to the meeting." - : "This user is already your contact, but your activities are not visible to them yet."; + // isOrganizer: true = admit mode, false = visibility mode + const message = this.isOrganizer + ? "This user is already your contact, but they are not yet admitted to the meeting." + : "This user is already your contact, but your activities are not visible to them yet."; this.$notify( { diff --git a/src/components/EntityGrid.vue b/src/components/EntityGrid.vue index ec5fe236..6c84eb7b 100644 --- a/src/components/EntityGrid.vue +++ b/src/components/EntityGrid.vue @@ -2,12 +2,55 @@ GiftedDialog.vue to provide a reusable grid layout * for displaying people, projects, and special entities with selection. * * @author Matthew Raymer */