diff --git a/.drone.yml b/.drone.yml index a254cb6..f33ddec 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,4 +1,5 @@ kind: pipeline +type: docker name: testing workspace: @@ -37,6 +38,7 @@ steps: --- kind: pipeline +type: docker name: release-latest depends_on: @@ -84,6 +86,7 @@ steps: --- kind: pipeline +type: docker name: release-version depends_on: @@ -125,3 +128,59 @@ steps: strip_prefix: apks/ source: apks/* target: /app/${DRONE_TAG##v} + +--- +kind: pipeline +type: exec +name: release-ios + + +trigger: + event: + - push + branch: + - master + +platform: + os: darwin + arch: amd64 + + +steps: + - name: build + commands: + - make build-ios + environment: + HOME: /Users/buildslave + - name: deploy + environment: + HOME: /Users/buildslave + LC_ALL: en_US.UTF-8 + LANG: en_US.UTF-8 + FASTLANE_SKIP_UPDATE_CHECK: true + FASTLANE_HIDE_CHANGELOG: true + MATCH_PASSWORD: + from_secret: match_password + FASTLANE_PASSWORD: + from_secret: fastlane_password + FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: + from_secret: fastlane_apple_password + FASTLANE_SESSION: + from_secret: fastlane_session + KEYCHAIN_PASSWORD: + from_secret: keychain_password + CONTACT_EMAIL: + from_secret: contact_email + CONTACT_FIRST_NAME: + from_secret: contact_first_name + CONTACT_LAST_NAME: + from_secret: contact_last_name + CONTACT_PHONE: + from_secret: contact_phone + commands: + - cd ios + - fastlane ios signing + - fastlane ios beta + +depends_on: + - testing \ No newline at end of file diff --git a/.gitignore b/.gitignore index b0658dd..ab3e5ac 100644 --- a/.gitignore +++ b/.gitignore @@ -70,4 +70,8 @@ build/ !**/ios/**/default.mode2v3 !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages \ No newline at end of file +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +ios/fastlane/README.md +ios/fastlane/report.xml +ios/Runner.ipa +ios/Runner.app.dSYM.zip diff --git a/Makefile b/Makefile index 36134c0..b7c2c4b 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,10 @@ GIT_LAST_COMMIT := $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//') FLUTTER ?= flutter -ifneq ($(DRONE_TAG),) - VERSION ?= $(subst v,,$(DRONE_TAG))-$(GIT_LAST_COMMIT) +ifneq ($(DRONE_BUILD_NUMBER),) + VERSION ?= $(DRONE_BUILD_NUMBER) else - ifneq ($(DRONE_BRANCH),) - VERSION ?= $(subst release/v,,$(DRONE_BRANCH))-$(GIT_LAST_COMMIT) - else - VERSION ?= master-$(GIT_LAST_COMMIT) - endif + VERSION ?= 1 endif .PHONY: test @@ -20,15 +16,19 @@ build-all: build-release build-debug build-profile .PHONY: build-release build-release: - $(FLUTTER) build apk --release --build-name=$(VERSION) --flavor main + $(FLUTTER) build apk --release --build-number=$(VERSION) --flavor main .PHONY: build-debug build-debug: - $(FLUTTER) build apk --debug --build-name=$(VERSION) --flavor unsigned + $(FLUTTER) build apk --debug --build-number=$(VERSION) --flavor unsigned .PHONY: build-profile build-profile: - $(FLUTTER) build apk --profile --build-name=$(VERSION) --flavor unsigned + $(FLUTTER) build apk --profile --build-number=$(VERSION) --flavor unsigned + +.PHONY: build-ios +build-ios: + $(FLUTTER) build ios --release --build-number=$(VERSION) --no-codesign .PHONY: format format: diff --git a/assets/vikunja_logo_full.png b/assets/vikunja_logo_full.png index 57e4652..7fd28cf 100644 Binary files a/assets/vikunja_logo_full.png and b/assets/vikunja_logo_full.png differ diff --git a/assets/vikunja_logo_full_white.png b/assets/vikunja_logo_full_white.png new file mode 100644 index 0000000..850f993 Binary files /dev/null and b/assets/vikunja_logo_full_white.png differ diff --git a/ios/Flutter/Flutter.podspec b/ios/Flutter/Flutter.podspec new file mode 100644 index 0000000..5ca3041 --- /dev/null +++ b/ios/Flutter/Flutter.podspec @@ -0,0 +1,18 @@ +# +# NOTE: This podspec is NOT to be published. It is only used as a local source! +# + +Pod::Spec.new do |s| + s.name = 'Flutter' + s.version = '1.0.0' + s.summary = 'High-performance, high-fidelity mobile apps.' + s.description = <<-DESC +Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. + DESC + s.homepage = 'https://flutter.io' + s.license = { :type => 'MIT' } + s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } + s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } + s.ios.deployment_target = '8.0' + s.vendored_frameworks = 'Flutter.framework' +end diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh index ba8483e..e22f24c 100755 --- a/ios/Flutter/flutter_export_environment.sh +++ b/ios/Flutter/flutter_export_environment.sh @@ -1,10 +1,11 @@ #!/bin/sh # This is a generated file; do not edit or check into version control. -export "FLUTTER_ROOT=/nix/store/nyvp7jf7sfxsbc6jsm1y4fc18631ap26-flutter-stable-1.12.13+hotfix.5-unwrapped" -export "FLUTTER_APPLICATION_PATH=/home/konrad/www/vikunja/app2" +export "FLUTTER_ROOT=/opt/flutter" +export "FLUTTER_APPLICATION_PATH=/home/jonasfranz/Projects/vikunja/app" export "FLUTTER_TARGET=lib/main.dart" export "FLUTTER_BUILD_DIR=build" export "SYMROOT=${SOURCE_ROOT}/../build/ios" -export "FLUTTER_FRAMEWORK_DIR=/home/konrad/.cache/flutter/artifacts/engine/ios" +export "OTHER_LDFLAGS=$(inherited) -framework Flutter" +export "FLUTTER_FRAMEWORK_DIR=/opt/flutter/bin/cache/artifacts/engine/ios" export "FLUTTER_BUILD_NAME=0.1.0" export "FLUTTER_BUILD_NUMBER=0.1.0" diff --git a/ios/Gemfile b/ios/Gemfile new file mode 100644 index 0000000..7a118b4 --- /dev/null +++ b/ios/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "fastlane" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..6697f0a --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,87 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.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 parse_KV_file(file, separator='=') + file_abs_path = File.expand_path(file) + if !File.exists? file_abs_path + return []; + end + generated_key_values = {} + skip_line_start_symbols = ["#", "/"] + File.foreach(file_abs_path) do |line| + next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } + plugin = line.split(pattern=separator) + if plugin.length == 2 + podname = plugin[0].strip() + path = plugin[1].strip() + podpath = File.expand_path("#{path}", file_abs_path) + generated_key_values[podname] = podpath + else + puts "Invalid plugin specification: #{line}" + end + end + generated_key_values +end + +target 'Runner' do + use_frameworks! + use_modular_headers! + + # Flutter Pod + + copied_flutter_dir = File.join(__dir__, 'Flutter') + copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') + copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') + unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) + # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. + # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. + # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. + + generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') + unless File.exist?(generated_xcode_build_settings_path) + raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) + cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; + + unless File.exist?(copied_framework_path) + FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) + end + unless File.exist?(copied_podspec_path) + FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) + end + end + + # Keep pod path relative so it can be checked into Podfile.lock. + pod 'Flutter', :path => 'Flutter' + + # Plugin Pods + + # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock + # referring to absolute paths on developers' machines. + system('rm -rf .symlinks') + system('mkdir -p .symlinks/plugins') + plugin_pods = parse_KV_file('../.flutter-plugins') + plugin_pods.each do |name, path| + symlink = File.join('.symlinks', 'plugins', name) + File.symlink(path, symlink) + pod name, :path => File.join(symlink, 'ios') + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 43e80ee..4715037 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -8,13 +8,8 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -29,8 +24,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -40,21 +33,21 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; + 1CD140BF817CCDA821C9152F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + BD0C880424A0CB4300291E83 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; C102A622A93B95B5704BDD24 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CA78C9A9831542FDDB6FB31E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,8 +55,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, ACA854A11123D371B9168194 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -82,6 +73,8 @@ 7CACC4C503C5D851EB73C215 /* Pods */ = { isa = PBXGroup; children = ( + CA78C9A9831542FDDB6FB31E /* Pods-Runner.debug.xcconfig */, + 1CD140BF817CCDA821C9152F /* Pods-Runner.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -89,10 +82,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -122,6 +112,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + BD0C880424A0CB4300291E83 /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -157,7 +148,6 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 85082CB7F9EE2F3E7985BDB9 /* [CP] Embed Pods Frameworks */, - 7C22F5DE30AEBAB42040EB3F /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -181,6 +171,7 @@ CreatedOnToolsVersion = 7.3.1; DevelopmentTeam = Z48VLBM2R7; LastSwiftMigration = 0910; + ProvisioningStyle = Manual; }; }; }; @@ -189,6 +180,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -211,7 +203,6 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -249,22 +240,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 7C22F5DE30AEBAB42040EB3F /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 85082CB7F9EE2F3E7985BDB9 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; @@ -272,8 +248,8 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${PODS_ROOT}/../Flutter/Flutter.framework", "${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework", ); name = "[CP] Embed Pods Frameworks"; @@ -283,7 +259,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { @@ -443,6 +419,8 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = Z48VLBM2R7; ENABLE_BITCODE = NO; @@ -458,6 +436,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = io.vikunja.flutteringVikunja; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "match Development io.vikunja.flutteringVikunja 1592303885"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = On; @@ -472,6 +451,9 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = Z48VLBM2R7; ENABLE_BITCODE = NO; @@ -487,6 +469,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = io.vikunja.flutteringVikunja; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "match AppStore io.vikunja.flutteringVikunja 1592303767"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 514e512..00504bd 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + ITSAppUsesNonExemptEncryption + CFBundleDevelopmentRegion en CFBundleDisplayName diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements new file mode 100644 index 0000000..903def2 --- /dev/null +++ b/ios/Runner/Runner.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + diff --git a/ios/fastlane/Appfile b/ios/fastlane/Appfile new file mode 100644 index 0000000..157727d --- /dev/null +++ b/ios/fastlane/Appfile @@ -0,0 +1,8 @@ +app_identifier("io.vikunja.flutteringVikunja") # The bundle identifier of your app +apple_id("email@jfdev.de") # Your Apple email address + +itc_team_id("117734679") # App Store Connect Team ID +team_id("Z48VLBM2R7") # Developer Portal Team ID + +# For more information about the Appfile, see: +# https://docs.fastlane.tools/advanced/#appfile diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile new file mode 100644 index 0000000..959662a --- /dev/null +++ b/ios/fastlane/Fastfile @@ -0,0 +1,45 @@ +# This file contains the fastlane.tools configuration +# You can find the documentation at https://docs.fastlane.tools +# +# For a list of all available actions, check out +# +# https://docs.fastlane.tools/actions +# +# For a list of all available plugins, check out +# +# https://docs.fastlane.tools/plugins/available-plugins +# + +# Uncomment the line if you want fastlane to automatically update itself +# update_fastlane + +default_platform(:ios) + +platform :ios do + desc "Push a new beta build to TestFlight" + lane :beta do + match(type: "appstore", readonly: true) + gym + upload_to_testflight( + beta_app_feedback_email: "hello@vikunja.io", + beta_app_description: "Automated Vikunja App Build", + demo_account_required: true, + distribute_external: true, + groups: ["PublicBeta"], + changelog: "Automated Vikunja Build", + beta_app_review_info: { + contact_email: ENV["CONTACT_EMAIL"], + contact_first_name: ENV["CONTACT_FIRST_NAME"], + contact_last_name: ENV["CONTACT_LAST_NAME"], + contact_phone: ENV["CONTACT_PHONE"], + demo_account_name: "demo", + demo_account_password: "demo", + notes: "Please use https://try.vikunja.io as URL" + } + ) + end + lane :signing do + match(type: "appstore", readonly: true) + match(type: "development", readonly: true) + end +end diff --git a/ios/fastlane/Matchfile b/ios/fastlane/Matchfile new file mode 100644 index 0000000..ee96f21 --- /dev/null +++ b/ios/fastlane/Matchfile @@ -0,0 +1,13 @@ +git_url("git@git.jfdev.de:JonasFranzDEV/match.git") + +storage_mode("git") + +type("development") # The default type, can be: appstore, adhoc, enterprise or development + +# app_identifier(["tools.fastlane.app", "tools.fastlane.app2"]) +# username("user@fastlane.tools") # Your Apple Developer Portal username + +# For all available options run `fastlane match --help` +# Remove the # in the beginning of the line to enable the other options + +# The docs are available on https://docs.fastlane.tools/actions/match diff --git a/lib/api/client.dart b/lib/api/client.dart index 7ba7e4f..b38e7d8 100644 --- a/lib/api/client.dart +++ b/lib/api/client.dart @@ -67,8 +67,15 @@ class Client { dynamic _handleResponse(http.Response response) { if (response.statusCode < 200 || - response.statusCode > 400 || + response.statusCode >= 400 || json == null) { + if (response.statusCode ~/ 100 == 4) { + Map error = _decoder.convert(response.body); + throw new InvalidRequestApiException( + response.statusCode, + response.request.url.toString(), + error["message"] ?? "Unknown Error"); + } throw new ApiException( response.statusCode, response.request.url.toString()); } @@ -86,6 +93,17 @@ class Client { } } +class InvalidRequestApiException extends ApiException { + final String message; + InvalidRequestApiException(int errorCode, String path, this.message) + : super(errorCode, path); + + @override + String toString() { + return this.message; + } +} + class ApiException implements Exception { final int errorCode; final String path; diff --git a/lib/components/ErrorDialog.dart b/lib/components/ErrorDialog.dart new file mode 100644 index 0000000..640c3c1 --- /dev/null +++ b/lib/components/ErrorDialog.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +class ErrorDialog extends StatelessWidget { + final dynamic error; + + ErrorDialog({this.error}); + + @override + Widget build(BuildContext context) { + return AlertDialog( + content: Text(error.toString()), + actions: [ + FlatButton( + child: Text('Close'), + onPressed: () => Navigator.of(context).maybePop(), + ) + ], + ); + } +} diff --git a/lib/constants.dart b/lib/constants.dart new file mode 100644 index 0000000..fb17b2a --- /dev/null +++ b/lib/constants.dart @@ -0,0 +1,2 @@ +const SENTRY_DSN = + 'https://b070ed4bd1d043428db6fe7d1ce57908@sentry.kolaente.de/5'; diff --git a/lib/main.dart b/lib/main.dart index c7b2f6c..89cc5c4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,54 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:sentry/sentry.dart'; +import 'package:vikunja_app/constants.dart'; import 'package:vikunja_app/global.dart'; import 'package:vikunja_app/pages/home.dart'; import 'package:vikunja_app/pages/user/login.dart'; import 'package:vikunja_app/theme/theme.dart'; -void main() => runApp(VikunjaGlobal( +void main() { + if (!kReleaseMode) { + // only log errors in release mode + _startApp(); + return; + } + var sentry = new SentryClient(dsn: SENTRY_DSN); + + FlutterError.onError = (details, {bool forceReport = false}) { + try { + sentry.captureException( + exception: details.exception, + stackTrace: details.stack, + ); + } catch (e) { + print('Sending report to sentry.io failed: $e'); + } finally { + // Also use Flutter's pretty error logging to the device's console. + FlutterError.dumpErrorToConsole(details, forceReport: forceReport); + } + }; + + runZoned( + _startApp, + onError: (Object error, StackTrace stackTrace) { + try { + sentry.captureException( + exception: error, + stackTrace: stackTrace, + ); + print('Error sent to sentry.io: $error'); + } catch (e) { + print('Sending report to sentry.io failed: $e'); + print('Original error: $error'); + } + }, + ); +} + +_startApp() => runApp(VikunjaGlobal( child: new VikunjaApp(home: HomePage()), login: new VikunjaApp(home: LoginPage()))); @@ -17,6 +61,7 @@ class VikunjaApp extends StatelessWidget { return new MaterialApp( title: 'Vikunja', theme: buildVikunjaTheme(), + darkTheme: buildVikunjaDarkTheme(), home: this.home, ); } diff --git a/lib/pages/home.dart b/lib/pages/home.dart index eeeb4b3..0879f16 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:after_layout/after_layout.dart'; import 'package:vikunja_app/components/AddDialog.dart'; +import 'package:vikunja_app/components/ErrorDialog.dart'; import 'package:vikunja_app/pages/namespace/namespace.dart'; import 'package:vikunja_app/pages/namespace/namespace_edit.dart'; import 'package:vikunja_app/pages/placeholder.dart'; @@ -162,7 +163,8 @@ class HomePageState extends State with AfterLayoutMixin { Scaffold.of(context).showSnackBar(SnackBar( content: Text('The namespace was created successfully!'), )); - }); + }).catchError((error) => showDialog( + context: context, builder: (context) => ErrorDialog(error: error))); } Future _loadNamespaces() { diff --git a/lib/pages/user/login.dart b/lib/pages/user/login.dart index aca7e76..fbcae00 100644 --- a/lib/pages/user/login.dart +++ b/lib/pages/user/login.dart @@ -34,7 +34,9 @@ class _LoginPageState extends State { Padding( padding: EdgeInsets.symmetric(vertical: 30), child: Image( - image: AssetImage('assets/vikunja_logo_full.png'), + image: Theme.of(context).brightness == Brightness.dark + ? AssetImage('assets/vikunja_logo_full_white.png') + : AssetImage('assets/vikunja_logo_full.png'), height: 85.0, semanticLabel: 'Vikunja Logo', ), diff --git a/lib/theme/button.dart b/lib/theme/button.dart index a49812b..79b70a4 100644 --- a/lib/theme/button.dart +++ b/lib/theme/button.dart @@ -24,7 +24,9 @@ class FancyButton extends StatelessWidget { height: height, decoration: BoxDecoration(boxShadow: [ BoxShadow( - color: vButtonShadow, + color: Theme.of(context).brightness == Brightness.dark + ? vButtonShadowDark + : vButtonShadow, offset: Offset(-5, 5), blurRadius: 10, ), diff --git a/lib/theme/constants.dart b/lib/theme/constants.dart index 8272190..dbd1a3f 100644 --- a/lib/theme/constants.dart +++ b/lib/theme/constants.dart @@ -15,6 +15,7 @@ const vGreen = Color(0xFF00CE6E); const vButtonColor = vPrimary; const vButtonTextColor = vWhite; +const vButtonShadowDark = Color(0xFF0b2a4a); const vButtonShadow = Color(0xFFb2d9ff); /////////// diff --git a/lib/theme/theme.dart b/lib/theme/theme.dart index 55ba656..f342a1e 100644 --- a/lib/theme/theme.dart +++ b/lib/theme/theme.dart @@ -1,8 +1,16 @@ import 'package:flutter/material.dart'; import 'package:vikunja_app/theme/constants.dart'; -ThemeData buildVikunjaTheme() { - var base = ThemeData.light(); +ThemeData buildVikunjaTheme() => _buildVikunjaTheme(ThemeData.light()); + +ThemeData buildVikunjaDarkTheme() { + ThemeData base = _buildVikunjaTheme(ThemeData.dark()); + return base.copyWith( + accentColor: vWhite, + ); +} + +ThemeData _buildVikunjaTheme(ThemeData base) { return base.copyWith( errorColor: vRed, primaryColor: vPrimaryDark, diff --git a/pubspec.lock b/pubspec.lock index 92ad7a6..0b06ee7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -14,42 +14,42 @@ packages: name: archive url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.13" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "1.5.2" + version: "1.6.0" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.0" + version: "2.4.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "2.0.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.3" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.14.11" + version: "1.14.12" convert: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "2.1.4" cupertino_icons: dependency: "direct main" description: @@ -98,7 +98,7 @@ packages: name: flutter_secure_storage url: "https://pub.dartlang.org" source: hosted - version: "3.3.1+1" + version: "3.3.3" flutter_test: dependency: "direct dev" description: flutter @@ -110,7 +110,7 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.12.0+3" + version: "0.12.1" http_parser: dependency: transitive description: @@ -124,7 +124,7 @@ packages: name: image url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.12" matcher: dependency: transitive description: @@ -180,7 +180,14 @@ packages: name: quiver url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.1.3" + sentry: + dependency: "direct main" + description: + name: sentry + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" sky_engine: dependency: transitive description: flutter @@ -192,7 +199,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.5.5" + version: "1.7.0" stack_trace: dependency: transitive description: @@ -227,7 +234,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.11" + version: "0.2.15" typed_data: dependency: transitive description: @@ -235,6 +242,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.6" + usage: + dependency: transitive + description: + name: usage + url: "https://pub.dartlang.org" + source: hosted + version: "3.4.1" vector_math: dependency: transitive description: @@ -248,7 +262,7 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "3.5.0" + version: "3.6.1" yaml: dependency: transitive description: @@ -257,5 +271,5 @@ packages: source: hosted version: "2.2.0" sdks: - dart: ">=2.4.0 <3.0.0" + dart: ">=2.6.0 <3.0.0" flutter: ">=1.12.1" diff --git a/pubspec.yaml b/pubspec.yaml index 3d6e45d..bcab75f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,9 +10,10 @@ dependencies: flutter: sdk: flutter cupertino_icons: ^0.1.3 - flutter_secure_storage: 3.3.1+1 - http: 0.12.0+3 + flutter_secure_storage: ^3.3.3 + http: ^0.12.1 after_layout: ^1.0.7 + sentry: ^3.0.1 provider: ^4.0.5 dev_dependencies: @@ -34,6 +35,7 @@ flutter: - assets/graphics/hypnotize.png - assets/vikunja_logo.png - assets/vikunja_logo_full.png + - assets/vikunja_logo_full_white.png fonts: - family: Quicksand fonts: