diff --git a/.gitignore b/.gitignore index f8d21f9..78c532b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,9 @@ local.properties app/release vendor +.bundle +fastlane/README.md +fastlane/report.xml +fastlane/metadata/android/screenshots.html +fastlane/metadata/android/**/images/screenshots/ .fdroid-submission \ No newline at end of file diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..84d6c67 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.4.10 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..7a118b4 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "fastlane" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..769f157 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,345 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.8) + abbrev (0.1.2) + addressable (2.9.0) + public_suffix (>= 2.0.2, < 8.0) + artifactory (3.0.17) + atomos (0.1.3) + aws-eventstream (1.4.0) + aws-partitions (1.1267.0) + aws-sdk-core (3.254.0) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.992.0) + aws-sigv4 (~> 1.9) + base64 + bigdecimal + jmespath (~> 1, >= 1.6.1) + logger + aws-sdk-kms (1.130.0) + aws-sdk-core (~> 3, >= 3.254.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.227.0) + aws-sdk-core (~> 3, >= 3.254.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.12.1) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + base64 (0.3.0) + benchmark (0.5.0) + bigdecimal (4.1.2) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + csv (3.3.5) + declarative (0.0.20) + digest-crc (0.7.0) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.6.20240107) + dotenv (2.8.1) + emoji_regex (3.2.3) + excon (1.5.0) + logger + faraday (1.10.6) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.8) + faraday (>= 0.8.0) + http-cookie (>= 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.1) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.2.0) + multipart-post (~> 2.0) + faraday-net_http (1.0.2) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.4) + faraday_middleware (1.2.1) + faraday (~> 1.0) + fastimage (2.4.1) + fastlane (2.237.0) + CFPropertyList (>= 2.3, < 5.0.0) + abbrev (~> 0.1) + addressable (>= 2.9.0, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.197) + babosa (>= 1.0.3, < 2.0.0) + base64 (~> 0.2) + benchmark (>= 0.1.0) + bundler (>= 2.4.0, < 5.0.0) + colored (~> 1.2) + commander (~> 4.6) + csv (~> 3.3) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 2.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + fastlane-sirp (>= 1.1.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-env (>= 1.6.0, < 2.3.0) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + http-cookie (~> 1.0.5) + json (< 3.0.0) + jwt (>= 2.10.3, < 4) + logger (>= 1.6, < 2.0) + mini_magick (>= 4.9.4, < 5.0.0) + multi_json (~> 1.12) + multipart-post (>= 2.0.0, < 3.0.0) + mutex_m (~> 0.3) + naturally (~> 2.2) + nkf (~> 0.2) + optparse (>= 0.1.1, < 1.0.0) + ostruct (>= 0.1.0) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.5) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (~> 3) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.4.1) + xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) + fastlane-sirp (1.1.0) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.104.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-core (0.18.0) + addressable (~> 2.5, >= 2.5.1) + googleauth (~> 1.9) + httpclient (>= 2.8.3, < 3.a) + mini_mime (~> 1.0) + mutex_m + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + google-apis-iamcredentials_v1 (0.28.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-playcustomapp_v1 (0.18.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-storage_v1 (0.64.0) + google-apis-core (>= 0.15.0, < 2.a) + google-cloud-core (1.9.0) + google-cloud-env (>= 1.0, < 3.a) + google-cloud-errors (~> 1.0) + google-cloud-env (2.2.2) + base64 (~> 0.2) + faraday (>= 1.0, < 3.a) + google-cloud-errors (1.7.0) + google-cloud-storage (1.62.0) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-core (>= 0.18, < 2) + google-apis-iamcredentials_v1 (~> 0.18) + google-apis-storage_v1 (>= 0.42) + google-cloud-core (~> 1.6) + googleauth (~> 1.9) + mini_mime (~> 1.0) + google-logging-utils (0.2.0) + googleauth (1.17.1) + faraday (>= 1.0, < 3.a) + google-cloud-env (~> 2.2) + google-logging-utils (~> 0.1) + jwt (>= 1.4, < 4.0) + os (>= 0.9, < 2.0) + pstore (~> 0.1) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.8) + domain_name (~> 0.5) + httpclient (2.9.0) + mutex_m + jmespath (1.6.2) + json (2.20.0) + jwt (3.2.0) + base64 + logger (1.7.0) + mini_magick (4.13.2) + mini_mime (1.1.5) + multi_json (1.21.1) + multipart-post (2.4.1) + mutex_m (0.3.0) + nanaimo (0.4.0) + naturally (2.3.0) + nkf (0.3.0) + optparse (0.8.1) + os (1.1.4) + ostruct (0.6.3) + plist (3.7.2) + pstore (0.2.1) + public_suffix (7.0.5) + rake (13.4.2) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.8.0) + rexml (3.4.4) + rouge (3.28.0) + ruby2_keywords (0.0.5) + rubyzip (2.4.1) + security (0.1.5) + signet (0.22.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 4.0) + simctl (1.6.10) + CFPropertyList + naturally + terminal-notifier (2.0.0) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.2) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unicode-display_width (2.6.0) + word_wrap (1.0.0) + xcodeproj (1.28.1) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + base64 + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.4.0) + nkf + rexml (>= 3.3.6, < 4.0) + xcpretty (0.4.1) + rouge (~> 3.28.0) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + arm64-darwin-25 + ruby + +DEPENDENCIES + fastlane + +CHECKSUMS + CFPropertyList (3.0.8) sha256=2c99d0d980536d3d7ab252f7bd59ac8be50fbdd1ff487c98c949bb66bb114261 + abbrev (0.1.2) sha256=ad1b4eaaaed4cb722d5684d63949e4bde1d34f2a95e20db93aecfe7cbac74242 + addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af + artifactory (3.0.17) sha256=3023d5c964c31674090d655a516f38ca75665c15084140c08b7f2841131af263 + atomos (0.1.3) sha256=7d43b22f2454a36bace5532d30785b06de3711399cb1c6bf932573eda536789f + aws-eventstream (1.4.0) sha256=116bf85c436200d1060811e6f5d2d40c88f65448f2125bc77ffce5121e6e183b + aws-partitions (1.1267.0) sha256=15a4c6bef8c303b09a1452c675cecb1ace0238dc91e26fe4646c5d761cb2221e + aws-sdk-core (3.254.0) sha256=ee3e3220b8468a3c9e59daba18e6ec897bf5c7ce8adcc0670cfa2f1f092112fe + aws-sdk-kms (1.130.0) sha256=a2e83662ca31b77a2a19c9aa2f40a98165a67270c18c718fe1c70d0cbd7cd749 + aws-sdk-s3 (1.227.0) sha256=552b23bf9a37c7db4957e9291543e61c8de886cf31d1d45ea3b429df0feea939 + aws-sigv4 (1.12.1) sha256=6973ff95cb0fd0dc58ba26e90e9510a2219525d07620c8babeb70ef831826c00 + babosa (1.0.4) sha256=18dea450f595462ed7cb80595abd76b2e535db8c91b350f6c4b3d73986c5bc99 + base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b + benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c + bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd + bundler (4.0.16) sha256=d6ca5dd440c24f9abce9844cf44cc8e18c6a553de65a47efb4544137af92c47d + claide (1.1.0) sha256=6d3c5c089dde904d96aa30e73306d0d4bd444b1accb9b3125ce14a3c0183f82e + colored (1.2) sha256=9d82b47ac589ce7f6cab64b1f194a2009e9fd00c326a5357321f44afab2c1d2c + colored2 (3.1.2) sha256=b13c2bd7eeae2cf7356a62501d398e72fde78780bd26aec6a979578293c28b4a + commander (4.6.0) sha256=7d1ddc3fccae60cc906b4131b916107e2ef0108858f485fdda30610c0f2913d9 + csv (3.3.5) sha256=6e5134ac3383ef728b7f02725d9872934f523cb40b961479f69cf3afa6c8e73f + declarative (0.0.20) sha256=8021dd6cb17ab2b61233c56903d3f5a259c5cf43c80ff332d447d395b17d9ff9 + digest-crc (0.7.0) sha256=64adc23a26a241044cbe6732477ca1b3c281d79e2240bcff275a37a5a0d78c07 + domain_name (0.6.20240107) sha256=5f693b2215708476517479bf2b3802e49068ad82167bcd2286f899536a17d933 + dotenv (2.8.1) sha256=c5944793349ae03c432e1780a2ca929d60b88c7d14d52d630db0508c3a8a17d8 + emoji_regex (3.2.3) sha256=ecd8be856b7691406c6bf3bb3a5e55d6ed683ffab98b4aa531bb90e1ddcc564b + excon (1.5.0) sha256=c503ad1d0123bc8ab2a062ff3789dc891ec368cb9e13765ab88a9c58c8bb6d50 + faraday (1.10.6) sha256=7ff4802a6b312876a2241b3e641ce0d5045e168dd871b422c35b505e5261ad4d + faraday-cookie_jar (0.0.8) sha256=0140605823f8cc63c7028fccee486aaed8e54835c360cffc1f7c8c07c4299dbb + faraday-em_http (1.0.0) sha256=7a3d4c7079789121054f57e08cd4ef7e40ad1549b63101f38c7093a9d6c59689 + faraday-em_synchrony (1.0.1) sha256=bf3ce45dcf543088d319ab051f80985ea6d294930635b7a0b966563179f81750 + faraday-excon (1.1.0) sha256=b055c842376734d7f74350fe8611542ae2000c5387348d9ba9708109d6e40940 + faraday-httpclient (1.0.1) sha256=4c8ff1f0973ff835be8d043ef16aaf54f47f25b7578f6d916deee8399a04d33b + faraday-multipart (1.2.0) sha256=7d89a949693714176f612323ca13746a2ded204031a6ba528adee788694ef757 + faraday-net_http (1.0.2) sha256=63992efea42c925a20818cf3c0830947948541fdcf345842755510d266e4c682 + faraday-net_http_persistent (1.2.0) sha256=0b0cbc8f03dab943c3e1cc58d8b7beb142d9df068b39c718cd83e39260348335 + faraday-patron (1.0.0) sha256=dc2cd7b340bb3cc8e36bcb9e6e7eff43d134b6d526d5f3429c7a7680ddd38fa7 + faraday-rack (1.0.0) sha256=ef60ec969a2bb95b8dbf24400155aee64a00fc8ba6c6a4d3968562bcc92328c0 + faraday-retry (1.0.4) sha256=dc659233777fabf96c69c2ffe56c0a5d2c102af90321a42cc6c90157bcd716aa + faraday_middleware (1.2.1) sha256=d45b78c8ee864c4783fbc276f845243d4a7918a67301c052647bacabec0529e9 + fastimage (2.4.1) sha256=c64bebd46b6fd8943ab70c1e6e85ff728f970f2e48f92ecd249b6bc3a540ad20 + fastlane (2.237.0) sha256=bb1e867bc070fb328741b5e6e7606d5ba596941a9ecca0478f60ef22d1009db9 + fastlane-sirp (1.1.0) sha256=10bc94f9682efd8e1badfb31452a76dd8981f1f3a33717c765fde6d75b54d847 + gh_inspector (1.1.3) sha256=04cca7171b87164e053aa43147971d3b7f500fcb58177698886b48a9fc4a1939 + google-apis-androidpublisher_v3 (0.104.0) sha256=3bf7f0dee23ae71e070e279848374834853204e304831cf6aa76fa435a4d6eff + google-apis-core (0.18.0) sha256=96b057816feeeab448139ed5b5c78eab7fc2a9d8958f0fbc8217dedffad054ee + google-apis-iamcredentials_v1 (0.28.0) sha256=0a92ffe6cc39c569554af2a77a25dfc61519ed8bbb64ab04cffdd352dc5ef106 + google-apis-playcustomapp_v1 (0.18.0) sha256=44b277b9dee4a59ac5e9d98be1485edc5e382d2f9d73c79ae8908a455786a254 + google-apis-storage_v1 (0.64.0) sha256=75b11afa2edcee859b84c7a6972ee4456314eeef5f762827fd6cf5c5ffaf93f2 + google-cloud-core (1.9.0) sha256=ab55409f51488e8deefb6edcc1ce4771dfb5da2fe7b3bc075709a030c2b682a4 + google-cloud-env (2.2.2) sha256=94bed40e05a67e9468ce1cb38389fba9a90aa8fc62fc9e173204c1dca59e21e7 + google-cloud-errors (1.7.0) sha256=6e682f42d89aae08689f36f28495de629d756da076bafff0003bac7f8042ebb3 + google-cloud-storage (1.62.0) sha256=e2c3c08bf8fd40d50be92304084942203314d4fc0ee52028e99f9359c3ad1330 + google-logging-utils (0.2.0) sha256=675462b4ea5affa825a3442694ca2d75d0069455a1d0956127207498fca3df7b + googleauth (1.17.1) sha256=0f7e6fc70e204cee1b2d71f1e1de2d3b349d432404197fe68ebf7fa23d0821b9 + highline (2.0.3) sha256=2ddd5c127d4692721486f91737307236fe005352d12a4202e26c48614f719479 + http-cookie (1.0.8) sha256=b14fe0445cf24bf9ae098633e9b8d42e4c07c3c1f700672b09fbfe32ffd41aa6 + httpclient (2.9.0) sha256=4b645958e494b2f86c2f8a2f304c959baa273a310e77a2931ddb986d83e498c8 + jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1 + json (2.20.0) sha256=9362bc6e55a952b056abf9167cf053358181c904cb70cd6eee0808ea830fc32b + jwt (3.2.0) sha256=5419b1fe37b1da0982bd07051f573a8b8789ab724c2aa7e785e4784a3ed217d7 + logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 + mini_magick (4.13.2) sha256=71d6258e0e8a3d04a9a0a09784d5d857b403a198a51dd4f882510435eb95ddd9 + mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef + multi_json (1.21.1) sha256=e6126a31808e3b4d19f483c775ceac34df190dffa62adfb63a165ee14ba68080 + multipart-post (2.4.1) sha256=9872d03a8e552020ca096adadbf5e3cb1cd1cdd6acd3c161136b8a5737cdb4a8 + mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751 + nanaimo (0.4.0) sha256=faf069551bab17f15169c1f74a1c73c220657e71b6e900919897a10d991d0723 + naturally (2.3.0) sha256=459923cf76c2e6613048301742363200c3c7e4904c324097d54a67401e179e01 + nkf (0.3.0) sha256=357a8dbeba38b727b75930f665146546076a394a1c243faf634ff176e3588895 + optparse (0.8.1) sha256=42bea10d53907ccff4f080a69991441d611fbf8733b60ed1ce9ee365ce03bd1a + os (1.1.4) sha256=57816d6a334e7bd6aed048f4b0308226c5fb027433b67d90a9ab435f35108d3f + ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912 + plist (3.7.2) sha256=d37a4527cc1116064393df4b40e1dbbc94c65fa9ca2eec52edf9a13616718a42 + pstore (0.2.1) sha256=03904d0f2c66579e96d1e6704cdabc0c88df7ea8ed8782d9f3569f6f6c702c1a + public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623 + rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701 + representable (3.2.0) sha256=cc29bf7eebc31653586849371a43ffe36c60b54b0a6365b5f7d95ec34d1ebace + retriable (3.8.0) sha256=9f2f1b0207594c7817f17f671587b8ec7587387ac6cebda6c941a802bb98a8e5 + rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142 + rouge (3.28.0) sha256=0d6de482c7624000d92697772ab14e48dca35629f8ddf3f4b21c99183fd70e20 + ruby2_keywords (0.0.5) sha256=ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef + rubyzip (2.4.1) sha256=8577c88edc1fde8935eb91064c5cb1aef9ad5494b940cf19c775ee833e075615 + security (0.1.5) sha256=3a977a0eca7706e804c96db0dd9619e0a94969fe3aac9680fcfc2bf9b8a833b7 + signet (0.22.0) sha256=b76d495ccb07ad35dbc89f3e920665a9d8ed717141955034005d7843dcfe4780 + simctl (1.6.10) sha256=b99077f4d13ad81eace9f86bf5ba4df1b0b893a4d1b368bd3ed59b5b27f9236b + terminal-notifier (2.0.0) sha256=7a0d2b2212ab9835c07f4b2e22a94cff64149dba1eed203c04835f7991078cea + terminal-table (3.0.2) sha256=f951b6af5f3e00203fb290a669e0a85c5dd5b051b3b023392ccfd67ba5abae91 + trailblazer-option (0.1.2) sha256=20e4f12ea4e1f718c8007e7944ca21a329eee4eed9e0fa5dde6e8ad8ac4344a3 + tty-cursor (0.7.1) sha256=79534185e6a777888d88628b14b6a1fdf5154a603f285f80b1753e1908e0bf48 + tty-screen (0.8.2) sha256=c090652115beae764336c28802d633f204fb84da93c6a968aa5d8e319e819b50 + tty-spinner (0.9.3) sha256=0e036f047b4ffb61f2aa45f5a770ec00b4d04130531558a94bfc5b192b570542 + uber (0.1.0) sha256=5beeb407ff807b5db994f82fa9ee07cfceaa561dad8af20be880bc67eba935dc + unicode-display_width (2.6.0) sha256=12279874bba6d5e4d2728cef814b19197dbb10d7a7837a869bab65da943b7f5a + word_wrap (1.0.0) sha256=f556d4224c812e371000f12a6ee8102e0daa724a314c3f246afaad76d82accc7 + xcodeproj (1.28.1) sha256=6f12670f00739d9817ca27ac89d6ef01cc86050e22a0bc08a3131487e5b5cddc + xcpretty (0.4.1) sha256=b14c50e721f6589ee3d6f5353e2c2cfcd8541fa1ea16d6c602807dd7327f3892 + xcpretty-travis-formatter (1.0.1) sha256=aacc332f17cb7b2cba222994e2adc74223db88724fe76341483ad3098e232f93 + +BUNDLED WITH + 4.0.16 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5a00b7a..f27c687 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -55,6 +55,7 @@ dependencies { testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(libs.fastlane.screengrab) androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) diff --git a/app/src/androidTest/java/com/ah/taplock/ScreenshotTest.kt b/app/src/androidTest/java/com/ah/taplock/ScreenshotTest.kt new file mode 100644 index 0000000..dad8be2 --- /dev/null +++ b/app/src/androidTest/java/com/ah/taplock/ScreenshotTest.kt @@ -0,0 +1,95 @@ +package com.ah.taplock + +import android.content.Context +import androidx.compose.ui.test.junit4.v2.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performScrollTo +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.ah.taplock.ui.theme.TapLockTheme +import org.junit.Before +import org.junit.ClassRule +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import tools.fastlane.screengrab.Screengrab +import tools.fastlane.screengrab.locale.LocaleTestRule + +/** + * Drives [TapLockScreen] and captures store screenshots via fastlane screengrab. + * Run through the `fastlane screenshots` lane, not as part of the normal test suite — + * it produces images rather than assertions. The [LocaleTestRule] switches the device + * locale for each locale listed in Screengrabfile so descriptions render translated. + */ +@RunWith(AndroidJUnit4::class) +class ScreenshotTest { + + @get:Rule + val composeTestRule = createComposeRule() + + private val context: Context + get() = InstrumentationRegistry.getInstrumentation().targetContext + + private fun setScreenContent() { + composeTestRule.setContent { + TapLockTheme { + TapLockScreen() + } + } + } + + @Before + fun setup() { + // Seed a configured state so the widget and floating-button previews render richly: + // custom-looking icon shown, glass widget style, floating button enabled, and the + // lock-screen double-tap zone controls revealed. Onboarding/info are dismissed. + context.getSharedPreferences( + context.getString(R.string.shared_pref_name), + Context.MODE_PRIVATE + ).edit().clear() + .putBoolean(context.getString(R.string.has_completed_onboarding), true) + .putBoolean(context.getString(R.string.has_seen_info), true) + .putBoolean(context.getString(R.string.show_widget_icon), true) + .putString(context.getString(R.string.widget_style), TapLockWidgetStyle.GLASS.name) + .putBoolean(context.getString(R.string.floating_button_enabled), true) + .putInt(context.getString(R.string.floating_button_size_dp), 72) + .putInt(context.getString(R.string.floating_button_opacity_percent), 90) + .putBoolean(context.getString(R.string.lock_screen_double_tap), true) + .commit() + } + + @Test + fun captureScreenshots() { + setScreenContent() + + // 1 — top of the settings screen (permissions + quick access). + composeTestRule.waitForIdle() + Screengrab.screenshot("01_settings") + + // 2 — the live widget preview (custom icon + glass style) with the style chips above it. + composeTestRule.onNodeWithTag("widget_style_preview").performScrollTo() + composeTestRule.waitForIdle() + Screengrab.screenshot("02_widget_styles") + + // 3 — Quick Settings tile setup. + composeTestRule.onNodeWithTag("button_quick_settings_tile").performScrollTo() + composeTestRule.waitForIdle() + Screengrab.screenshot("03_quick_tile") + + // 4 — ambient triggers with the lock-screen zone controls revealed. + composeTestRule.onNodeWithTag("switch_lock_screen").performScrollTo() + composeTestRule.waitForIdle() + Screengrab.screenshot("04_ambient_triggers") + + // 5 — behavior section (timeout, vibration, lock delay). + composeTestRule.onNodeWithTag("slider_timeout").performScrollTo() + composeTestRule.waitForIdle() + Screengrab.screenshot("05_behavior") + } + + companion object { + @get:ClassRule + @JvmStatic + val localeTestRule = LocaleTestRule() + } +} diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..4ace2ce --- /dev/null +++ b/app/src/debug/AndroidManifest.xml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/app/src/main/java/com/ah/taplock/MainActivity.kt b/app/src/main/java/com/ah/taplock/MainActivity.kt index 996b29d..62feb9d 100644 --- a/app/src/main/java/com/ah/taplock/MainActivity.kt +++ b/app/src/main/java/com/ah/taplock/MainActivity.kt @@ -980,7 +980,9 @@ fun TapLockScreen() { style = widgetStyle, showIcon = showIcon, iconBitmap = widgetIconBitmap ?: defaultAppIconBitmap, - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .testTag("widget_style_preview") ) if (showIcon) { @@ -1055,7 +1057,8 @@ fun TapLockScreen() { Button( onClick = { requestQuickSettingsTilePrompt() }, enabled = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && - !isTileAdded + !isTileAdded, + modifier = Modifier.testTag("button_quick_settings_tile") ) { Text( if (isTileAdded) { diff --git a/fastlane/Fastfile b/fastlane/Fastfile new file mode 100644 index 0000000..ba96445 --- /dev/null +++ b/fastlane/Fastfile @@ -0,0 +1,10 @@ +default_platform(:android) + +platform :android do + desc "Build debug + test APKs and capture store screenshots (EN/ES) via screengrab" + lane :screenshots do + gradle(task: "assembleDebug") + gradle(task: "assembleDebugAndroidTest") + screengrab + end +end diff --git a/fastlane/Screengrabfile b/fastlane/Screengrabfile new file mode 100644 index 0000000..41f6d77 --- /dev/null +++ b/fastlane/Screengrabfile @@ -0,0 +1,25 @@ +# fastlane screengrab configuration for TapLock. +# Run with: bundle exec fastlane screenshots +# (see fastlane/Fastfile). Requires a running emulator/device. + +app_package_name('com.ah.taplock') + +# Only run the dedicated screenshot test class, not the whole instrumented suite. +use_tests_in_classes(['com.ah.taplock.ScreenshotTest']) +test_instrumentation_runner('androidx.test.runner.AndroidJUnitRunner') + +# Capture these locales. Must match fastlane metadata folder locales. +locales(['en-US', 'es-ES']) + +# Clear previously generated screenshots before each run. +clear_previous_screenshots(true) + +# Output into the fastlane metadata tree so F-Droid / stores pick them up. +output_directory('fastlane/metadata/android') + +# Reinstall the app + test APKs each run. +reinstall_app(true) + +# Explicit APK paths (built by the `screenshots` lane / assembleDebug tasks). +app_apk_path('app/build/outputs/apk/debug/app-debug.apk') +tests_apk_path('app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk') diff --git a/fastlane/metadata/android/en-US/changelogs/17.txt b/fastlane/metadata/android/en-US/changelogs/17.txt new file mode 100644 index 0000000..653631b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/17.txt @@ -0,0 +1,3 @@ +* Detect Android Advanced Protection and clearly explain that it blocks TapLock's accessibility service +* Spanish language support +* Dependency and build updates diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt new file mode 100644 index 0000000..3a09515 --- /dev/null +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -0,0 +1,20 @@ +TapLock is a minimalist utility that lets you lock your screen with a double tap — perfect for one-handed use and quick screen locking without reaching for the power button. + +Create a resizable, transparent home screen widget and double-tap it to lock your phone instantly. TapLock also offers several other ways to lock: + +* Home screen widget (resizable, with optional icon and multiple styles) +* Quick Settings tile +* Draggable floating button +* Double-tap the status bar +* Double-tap the lock screen, edges, or corners + +Additional features: + +* Adjustable double-tap timeout and lock delay +* Optional vibration feedback with light, medium, and strong patterns +* Per-app exclusions so taps are ignored in apps you choose +* Available in English and Spanish + +TapLock uses Android's accessibility service to power off the screen. This permission is required for the app to function, and TapLock does not collect any personal information or track any other interaction you have with your device. The full source code is available for transparency. + +Note: On devices with Android's Advanced Protection enabled, the system blocks all third-party accessibility services, so TapLock cannot lock the screen while Advanced Protection is turned on. diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png new file mode 100644 index 0000000..bd1163d Binary files /dev/null and b/fastlane/metadata/android/en-US/images/icon.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/01_settings_1783716136408.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/01_settings_1783716136408.png new file mode 100644 index 0000000..6079a73 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/01_settings_1783716136408.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/02_widget_styles_1783716136552.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/02_widget_styles_1783716136552.png new file mode 100644 index 0000000..066e34d Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/02_widget_styles_1783716136552.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/03_quick_tile_1783716136686.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/03_quick_tile_1783716136686.png new file mode 100644 index 0000000..5cf3501 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/03_quick_tile_1783716136686.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/04_ambient_triggers_1783716136826.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/04_ambient_triggers_1783716136826.png new file mode 100644 index 0000000..46018f0 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/04_ambient_triggers_1783716136826.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/05_behavior_1783716136969.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/05_behavior_1783716136969.png new file mode 100644 index 0000000..4e45e7d Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/05_behavior_1783716136969.png differ diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt new file mode 100644 index 0000000..f73c33a --- /dev/null +++ b/fastlane/metadata/android/en-US/short_description.txt @@ -0,0 +1 @@ +Lock your screen instantly with a double tap. diff --git a/fastlane/metadata/android/en-US/title.txt b/fastlane/metadata/android/en-US/title.txt new file mode 100644 index 0000000..7964d1c --- /dev/null +++ b/fastlane/metadata/android/en-US/title.txt @@ -0,0 +1 @@ +TapLock diff --git a/fastlane/metadata/android/es-ES/changelogs/17.txt b/fastlane/metadata/android/es-ES/changelogs/17.txt new file mode 100644 index 0000000..b00ca7c --- /dev/null +++ b/fastlane/metadata/android/es-ES/changelogs/17.txt @@ -0,0 +1,3 @@ +* Detecta la Protección avanzada de Android y explica claramente que bloquea el servicio de accesibilidad de TapLock +* Compatibilidad con el idioma español +* Actualizaciones de dependencias y de compilación diff --git a/fastlane/metadata/android/es-ES/full_description.txt b/fastlane/metadata/android/es-ES/full_description.txt new file mode 100644 index 0000000..6823bb2 --- /dev/null +++ b/fastlane/metadata/android/es-ES/full_description.txt @@ -0,0 +1,20 @@ +TapLock es una utilidad minimalista que te permite bloquear la pantalla con un doble toque, ideal para el uso con una sola mano y para bloquear la pantalla rápidamente sin buscar el botón de encendido. + +Crea un widget transparente y redimensionable para la pantalla de inicio y tócalo dos veces para bloquear el teléfono al instante. TapLock también ofrece otras formas de bloquear: + +* Widget de pantalla de inicio (redimensionable, con icono opcional y varios estilos) +* Mosaico de Ajustes rápidos +* Botón flotante arrastrable +* Doble toque en la barra de estado +* Doble toque en la pantalla de bloqueo, los bordes o las esquinas + +Funciones adicionales: + +* Tiempo límite de doble toque y retardo de bloqueo ajustables +* Vibración opcional con patrones ligero, medio y fuerte +* Exclusiones por app para ignorar los toques en las apps que elijas +* Disponible en inglés y español + +TapLock usa el servicio de accesibilidad de Android para apagar la pantalla. Este permiso es necesario para que la app funcione, y TapLock no recopila ninguna información personal ni registra ninguna otra interacción que tengas con el dispositivo. El código fuente completo está disponible para mayor transparencia. + +Nota: en dispositivos con la Protección avanzada de Android activada, el sistema bloquea todos los servicios de accesibilidad de terceros, por lo que TapLock no puede bloquear la pantalla mientras la Protección avanzada esté activada. diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/01_settings_1783716157141.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/01_settings_1783716157141.png new file mode 100644 index 0000000..cb66de1 Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/01_settings_1783716157141.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/02_widget_styles_1783716157279.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/02_widget_styles_1783716157279.png new file mode 100644 index 0000000..f1eeb16 Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/02_widget_styles_1783716157279.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/03_quick_tile_1783716157411.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/03_quick_tile_1783716157411.png new file mode 100644 index 0000000..4cf630c Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/03_quick_tile_1783716157411.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/04_ambient_triggers_1783716157545.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/04_ambient_triggers_1783716157545.png new file mode 100644 index 0000000..5310214 Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/04_ambient_triggers_1783716157545.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/05_behavior_1783716157677.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/05_behavior_1783716157677.png new file mode 100644 index 0000000..6046055 Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/05_behavior_1783716157677.png differ diff --git a/fastlane/metadata/android/es-ES/short_description.txt b/fastlane/metadata/android/es-ES/short_description.txt new file mode 100644 index 0000000..83391b7 --- /dev/null +++ b/fastlane/metadata/android/es-ES/short_description.txt @@ -0,0 +1 @@ +Bloquea la pantalla al instante con un doble toque. diff --git a/fastlane/metadata/android/es-ES/title.txt b/fastlane/metadata/android/es-ES/title.txt new file mode 100644 index 0000000..7964d1c --- /dev/null +++ b/fastlane/metadata/android/es-ES/title.txt @@ -0,0 +1 @@ +TapLock diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9601a91..338bfdf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,6 +5,7 @@ coreKtx = "1.19.0" junit = "4.13.2" junitVersion = "1.3.0" espressoCore = "3.7.0" +screengrab = "2.1.1" lifecycleRuntimeKtx = "2.11.0" activityCompose = "1.13.0" composeBom = "2026.06.00" @@ -14,6 +15,7 @@ androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +fastlane-screengrab = { group = "tools.fastlane", name = "screengrab", version.ref = "screengrab" } androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } diff --git a/scripts/capture-home-widget.sh b/scripts/capture-home-widget.sh new file mode 100755 index 0000000..17ae8c8 --- /dev/null +++ b/scripts/capture-home-widget.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash +# +# Capture a "hero" screenshot of the TapLock widget on the launcher home screen. +# +# This is a MANUAL one-off helper, not part of the deterministic `fastlane screenshots` +# lane. It drives the real launcher's widget-pin flow via adb + UI Automator, which is +# inherently launcher- and timing-dependent (it matches button text and the Pixel/Nexus +# launcher pin dialog). Expect to eyeball the result and occasionally re-run. +# +# Prerequisites: +# - An emulator/device already booted and visible to `adb devices`. +# - The debug APK installed (e.g. run `./gradlew installDebug` or the screenshots lane first). +# +# Usage: +# ANDROID_HOME=~/Library/Android/sdk ./scripts/capture-home-widget.sh [output.png] +# +set -euo pipefail + +PKG="com.ah.taplock" +OUT="${1:-fastlane/metadata/android/en-US/images/phoneScreenshots/00_home_widget.png}" +# In-app button label differs first-time vs. when a widget already exists. +ADD_WIDGET_LABEL="Add Widget to Home Screen" +ADD_ANOTHER_LABEL="Add Another Widget" +PIN_CONFIRM_LABEL="Add to home screen" # launcher pin-dialog confirm button + +ADB="${ANDROID_HOME:-$HOME/Library/Android/sdk}/platform-tools/adb" +command -v "$ADB" >/dev/null 2>&1 || ADB="adb" + +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT + +die() { echo "error: $*" >&2; exit 1; } + +"$ADB" get-state >/dev/null 2>&1 || die "no device/emulator connected (check 'adb devices')" +"$ADB" shell pm path "$PKG" >/dev/null 2>&1 || die "$PKG not installed; build/install the debug APK first" + +# Center coordinates of a uiautomator node whose text matches $1, from the dumped XML in $2. +tap_text() { + local label="$2" xml="$3" + local bounds + bounds="$("$ADB" pull "$xml" "$TMP/ui.xml" >/dev/null 2>&1; \ + grep -oE "text=\"$label\"[^>]*bounds=\"\[[0-9]+,[0-9]+\]\[[0-9]+,[0-9]+\]\"" "$TMP/ui.xml" \ + | grep -oE '[0-9]+' | tr '\n' ' ' || true)" + [ -n "$bounds" ] || return 1 + # shellcheck disable=SC2086 + set -- $bounds + local cx=$(( ($1 + $3) / 2 )) cy=$(( ($2 + $4) / 2 )) + echo " tapping '$label' at $cx,$cy" + "$ADB" shell input tap "$cx" "$cy" +} + +echo "==> Allowing $PKG to bind app widgets" +"$ADB" shell appwidget grantbind --package "$PKG" --user current >/dev/null 2>&1 || true + +# Dim the wallpaper to a clean solid dark backdrop. Besides looking tidier, this works +# around an emulator GPU bug that smears the gradient wallpaper on some home pages. +# Restored on exit. +echo "==> Dimming wallpaper for a clean backdrop" +"$ADB" shell cmd wallpaper set-dim-amount 1.0 >/dev/null 2>&1 || true +trap '"$ADB" shell cmd wallpaper set-dim-amount 0.0 >/dev/null 2>&1 || true; rm -rf "$TMP"' EXIT + +echo "==> Launching app (fresh, scrolled to top)" +"$ADB" shell am force-stop "$PKG" >/dev/null 2>&1 || true +sleep 1 +"$ADB" shell am start -n "$PKG/.MainActivity" >/dev/null +sleep 3 + +echo "==> Locating the in-app add-widget button" +"$ADB" shell uiautomator dump /sdcard/ui.xml >/dev/null 2>&1 +tap_text tap "$ADD_WIDGET_LABEL" /sdcard/ui.xml \ + || tap_text tap "$ADD_ANOTHER_LABEL" /sdcard/ui.xml \ + || die "could not find the add-widget button ('$ADD_WIDGET_LABEL' / '$ADD_ANOTHER_LABEL') — did the label change?" +sleep 3 + +echo "==> Confirming the launcher pin dialog" +"$ADB" shell uiautomator dump /sdcard/ui2.xml >/dev/null 2>&1 +tap_text tap "$PIN_CONFIRM_LABEL" /sdcard/ui2.xml \ + || die "could not find '$PIN_CONFIRM_LABEL' pin-dialog button" +sleep 2 + +echo "==> Going to the home screen and repainting" +# Restart the launcher so it repaints cleanly with the dimmed wallpaper before capture. +"$ADB" shell input keyevent KEYCODE_HOME; sleep 1 +"$ADB" shell am force-stop com.google.android.apps.nexuslauncher >/dev/null 2>&1 || true +sleep 2 +"$ADB" shell input keyevent KEYCODE_HOME; sleep 4 + +echo "==> Capturing $OUT" +mkdir -p "$(dirname "$OUT")" +"$ADB" exec-out screencap -p > "$OUT" +echo "Done: $OUT ($(wc -c < "$OUT" | tr -d ' ') bytes)" +echo "Review the image — the widget should appear top-left on the home screen."