diff --git a/.github/workflows/website-docs.yml b/.github/workflows/website-docs.yml new file mode 100644 index 0000000000..0f4aed0797 --- /dev/null +++ b/.github/workflows/website-docs.yml @@ -0,0 +1,84 @@ +name: Build Hugo Website + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + paths: + - 'docs/website/**' + - 'docs/developer-guide/**' + - 'CodenameOne/src/**' + - 'Ports/CLDC11/src/**' + - 'maven/javadoc-resources/**' + - '.github/scripts/build_javadocs.sh' + - 'scripts/website/**' + - '.github/workflows/website-docs.yml' + push: + branches: [main, master] + paths: + - 'docs/website/**' + - 'docs/developer-guide/**' + - 'CodenameOne/src/**' + - 'Ports/CLDC11/src/**' + - 'maven/javadoc-resources/**' + - '.github/scripts/build_javadocs.sh' + - 'scripts/website/**' + - '.github/workflows/website-docs.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Hugo + uses: peaceiris/actions-hugo@v3 + with: + hugo-version: 'latest' + extended: true + + - name: Set up Java 25 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '25' + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.3' + + - name: Install Asciidoctor tooling + run: | + set -euo pipefail + gem install --no-document asciidoctor asciidoctor-pdf rouge + + - name: Build website + run: | + set -euo pipefail + scripts/website/build.sh + env: + WEBSITE_INCLUDE_JAVADOCS: "true" + WEBSITE_INCLUDE_DEVGUIDE: "true" + + - name: Upload built site artifact + uses: actions/upload-artifact@v4 + with: + name: website-preview + path: docs/website/public + if-no-files-found: error + + - name: Deploy to Cloudflare Pages + if: ${{ github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master') }} + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: >- + pages deploy docs/website/public + --project-name=${{ vars.CLOUDFLARE_PAGES_PROJECT_NAME || secrets.CLOUDFLARE_PAGES_PROJECT_NAME || 'codenameone' }} + --branch=${{ github.ref_name }} diff --git a/.gitignore b/.gitignore index 53d7701c21..0ea567bf74 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,12 @@ pom.xml.tag !.brokk/review.md !.brokk/project.properties dependency-reduced-pom.xml + +# Hugo website generated artifacts +/docs/website/.hugo_build.lock +/docs/website/hugo_stats.json +/docs/website/resources/ +/docs/website/public/ +/docs/website/.cache/ +/docs/website/.venv/ +/docs/website/.venv-pagefind/ diff --git a/docs/website/archetypes/default.md b/docs/website/archetypes/default.md new file mode 100644 index 0000000000..25b67521d3 --- /dev/null +++ b/docs/website/archetypes/default.md @@ -0,0 +1,5 @@ ++++ +date = '{{ .Date }}' +draft = true +title = '{{ replace .File.ContentBaseName "-" " " | title }}' ++++ diff --git a/docs/website/assets/css/extended/cn1-blog-index.css b/docs/website/assets/css/extended/cn1-blog-index.css new file mode 100644 index 0000000000..8796698a2c --- /dev/null +++ b/docs/website/assets/css/extended/cn1-blog-index.css @@ -0,0 +1,155 @@ +.cn1-blog-index { + max-width: min(1220px, calc(100vw - 32px)); + margin: 0 auto; + padding: 1.2rem 0 2rem; +} + +.cn1-blog-index .post-header { + margin-bottom: 1.2rem; +} + +.cn1-blog-index .post-title { + margin-bottom: 0.5rem; +} + +.cn1-blog-index .post-description { + color: var(--secondary); +} + +.cn1-blog-index__grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 1rem; + margin-top: 1rem; +} + +.cn1-blog-index__card { + display: grid; + grid-template-columns: minmax(160px, 220px) minmax(0, 1fr); + gap: 0.9rem; + padding: 0.8rem; + border: 1px solid var(--border); + background: var(--entry); +} + +.cn1-blog-index__thumb-link { + display: block; + align-self: start; + overflow: hidden; + aspect-ratio: 16 / 9; + background: var(--tertiary); +} + +.cn1-blog-index__thumb { + width: 100%; + height: 100%; + object-fit: cover; + object-position: center; + display: block; + transform: scale(1.03); + transition: transform 220ms ease; +} + +.cn1-blog-index__card:hover .cn1-blog-index__thumb { + transform: scale(1.08); +} + +.cn1-blog-index__body { + min-width: 0; +} + +.cn1-blog-index__title { + margin: 0 0 0.35rem; + font-size: 1.1rem; + line-height: 1.35; +} + +.cn1-blog-index__title a { + color: var(--primary); + text-decoration: none; +} + +.cn1-blog-index__title a:hover { + color: var(--tertiary); +} + +.cn1-blog-index__meta { + display: flex; + align-items: center; + gap: 0.5rem; + margin: 0 0 0.45rem; + font-size: 0.82rem; + color: var(--secondary); +} + +.cn1-blog-index__summary { + margin: 0; + color: var(--content); + font-size: 0.92rem; + line-height: 1.55; +} + +.cn1-blog-index__pagination { + display: flex; + justify-content: center; + align-items: center; + flex-wrap: wrap; + gap: 0.5rem; + margin-top: 1.5rem; +} + +.cn1-page-numbers { + display: flex; + align-items: center; + gap: 0.35rem; +} + +.cn1-page-link { + min-width: 2rem; + height: 2rem; + padding: 0 0.55rem; + border: 1px solid var(--border); + background: var(--entry); + color: var(--primary); + display: inline-flex; + align-items: center; + justify-content: center; + text-decoration: none; + font-size: 0.86rem; +} + +.cn1-page-ellipsis { + color: var(--secondary); + padding: 0 0.2rem; + font-weight: 600; +} + +.cn1-page-link:hover { + background: var(--tertiary); +} + +.cn1-page-link.is-current { + background: var(--primary); + color: var(--theme); + border-color: var(--primary); +} + +.cn1-page-link.is-disabled { + opacity: 0.45; +} + +.cn1-page-link--edge { + min-width: 3.2rem; +} + +@media (max-width: 980px) { + .cn1-blog-index__grid { + grid-template-columns: 1fr; + } +} + +@media (max-width: 700px) { + .cn1-blog-index__card { + grid-template-columns: 1fr; + } +} diff --git a/docs/website/assets/css/extended/cn1-blog-post.css b/docs/website/assets/css/extended/cn1-blog-post.css new file mode 100644 index 0000000000..3522c795c6 --- /dev/null +++ b/docs/website/assets/css/extended/cn1-blog-post.css @@ -0,0 +1,99 @@ +.cn1-blog-post .post-content { + max-width: 100%; + font-size: 17px; + line-height: 1.7; +} + +.cn1-blog-post .post-content > p, +.cn1-blog-post .post-content > ul, +.cn1-blog-post .post-content > ol, +.cn1-blog-post .post-content > blockquote, +.cn1-blog-post .post-content > pre, +.cn1-blog-post .post-content > table, +.cn1-blog-post .post-content > .highlight { + margin-block: 1.1em; +} + +.cn1-blog-post .post-content h2, +.cn1-blog-post .post-content h3, +.cn1-blog-post .post-content h4, +.cn1-blog-post .post-content h5 { + margin-top: 1.4em; + margin-bottom: 0.55em; + line-height: 1.28; + letter-spacing: normal; + text-wrap: balance; +} + +.cn1-blog-post .post-content h2 { + font-size: 30px; +} + +.cn1-blog-post .post-content h3 { + font-size: 24px; +} + +.cn1-blog-post .post-content h4 { + font-size: 20px; +} + +.cn1-blog-post .post-content h5 { + font-size: 18px; +} + +.cn1-blog-post .post-content ul, +.cn1-blog-post .post-content ol { + padding-inline-start: 1.2em; +} + +.cn1-blog-post .post-content li + li { + margin-top: 0.35em; +} + +.cn1-blog-post .post-content blockquote { + border-left: 3px solid rgba(28, 81, 255, 0.55); + padding: 10px 14px; + background: rgba(28, 81, 255, 0.06); + border-radius: 8px; +} + +body.dark .cn1-blog-post .post-content blockquote { + border-left-color: rgba(175, 193, 255, 0.65); + background: rgba(175, 193, 255, 0.09); +} + +.cn1-blog-post .post-content table { + display: block; + overflow-x: auto; + border-collapse: collapse; + width: 100%; +} + +.cn1-blog-post .post-content table th, +.cn1-blog-post .post-content table td { + border: 1px solid rgba(28, 81, 255, 0.18); + padding: 8px 10px; +} + +body.dark .cn1-blog-post .post-content table th, +body.dark .cn1-blog-post .post-content table td { + border-color: rgba(175, 193, 255, 0.25); +} + +@media (max-width: 900px) { + .cn1-blog-post .post-content { + font-size: 16px; + } + + .cn1-blog-post .post-content h2 { + font-size: 26px; + } + + .cn1-blog-post .post-content h3 { + font-size: 22px; + } + + .cn1-blog-post .post-content h4 { + font-size: 19px; + } +} diff --git a/docs/website/assets/css/extended/cn1-courses.css b/docs/website/assets/css/extended/cn1-courses.css new file mode 100644 index 0000000000..1947ef29cd --- /dev/null +++ b/docs/website/assets/css/extended/cn1-courses.css @@ -0,0 +1,298 @@ +:root { + --cn1-course-card-bg: rgba(68, 82, 123, 0.35); + --cn1-course-card-border: rgba(29, 82, 255, 0.55); + --cn1-course-soft-text: rgba(217, 228, 255, 0.85); + --cn1-course-link: #afc1ff; + --cn1-course-link-strong: #f5f8ff; +} + +body.light { + --cn1-course-card-bg: #f3f6ff; + --cn1-course-card-border: #d8e2ff; + --cn1-course-soft-text: #4d5f8e; + --cn1-course-link: #1d52ff; + --cn1-course-link-strong: #102154; +} + +.cn1-course-hub .post-header, +.cn1-course-lesson .post-header { + margin-bottom: 1.75rem; +} + +.cn1-course-overview__bar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + margin: 2rem 0 1.5rem; + padding: 1rem 1.25rem; + border: 1px solid var(--cn1-course-card-border); + border-radius: 14px; + background: var(--cn1-course-card-bg); +} + +.cn1-course-overview__bar p { + margin: 0; +} + +.cn1-course-overview__start { + display: inline-block; + border: 1px solid var(--cn1-course-link); + color: var(--cn1-course-link-strong); + text-decoration: none; + font-weight: 600; + padding: 0.55rem 1rem; + border-radius: 999px; +} + +.cn1-course-overview__start:hover { + opacity: 0.9; +} + +.cn1-course-overview__grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 1rem; +} + +.cn1-course-module-card { + border: 1px solid var(--cn1-course-card-border); + border-radius: 14px; + padding: 1rem 1rem 0.9rem; + background: var(--cn1-course-card-bg); +} + +.cn1-course-module-card header h2 { + margin: 0.1rem 0 0.15rem; + font-size: 1.12rem; + color: var(--cn1-course-link-strong); +} + +.cn1-course-module-card header p { + margin: 0; + color: var(--cn1-course-soft-text); + font-size: 0.9rem; +} + +.cn1-course-module-card__eyebrow { + margin: 0; + font-size: 0.78rem; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--cn1-course-link); +} + +.cn1-course-module-card ol { + margin: 0.85rem 0 0; + padding-left: 1.15rem; +} + +.cn1-course-module-card li + li { + margin-top: 0.7rem; +} + +.cn1-course-module-card li a { + color: var(--cn1-course-link-strong); + text-decoration: none; + font-weight: 600; +} + +.cn1-course-module-card li a:hover { + color: var(--cn1-course-link); +} + +.cn1-course-module-card li p { + margin: 0.25rem 0 0; + color: var(--cn1-course-soft-text); + font-size: 0.9rem; + line-height: 1.45; +} + +.cn1-training-path-card > p { + margin: 0.9rem 0 0; + color: var(--cn1-course-soft-text); + line-height: 1.55; +} + +.cn1-training-path-card__actions { + display: flex; + flex-wrap: wrap; + gap: 0.55rem; + margin-top: 1rem; +} + +.cn1-training-path-card__actions a { + display: inline-block; + text-decoration: none; + color: var(--cn1-course-link-strong); + border: 1px solid var(--cn1-course-card-border); + background: rgba(8, 17, 55, 0.2); + border-radius: 999px; + padding: 0.45rem 0.9rem; + font-size: 0.9rem; + font-weight: 600; +} + +body.light .cn1-training-path-card__actions a { + background: rgba(255, 255, 255, 0.75); +} + +.cn1-training-path-card__actions a:hover { + border-color: var(--cn1-course-link); + color: var(--cn1-course-link); +} + +.cn1-training-support { + margin-top: 1rem; +} + +.cn1-course-lesson__kicker { + margin: 0; + color: var(--cn1-course-link); + font-weight: 600; +} + +.cn1-course-lesson__meta { + margin: 0.4rem 0 0; + color: var(--cn1-course-soft-text); +} + +.cn1-course-lesson__layout { + display: grid; + grid-template-columns: 320px minmax(0, 1fr); + gap: 1.2rem; +} + +.cn1-course-lesson__sidebar { + position: sticky; + top: 92px; + max-height: calc(100vh - 110px); + overflow: auto; + border: 1px solid var(--cn1-course-card-border); + border-radius: 14px; + padding: 0.9rem; + background: var(--cn1-course-card-bg); +} + +.cn1-course-lesson__back { + display: inline-block; + margin-bottom: 0.75rem; + text-decoration: none; + color: var(--cn1-course-link); + font-weight: 600; +} + +.cn1-course-lesson__module + .cn1-course-lesson__module { + margin-top: 1rem; + padding-top: 0.8rem; + border-top: 1px solid var(--cn1-course-card-border); +} + +.cn1-course-lesson__module h2 { + margin: 0; + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--cn1-course-link); +} + +.cn1-course-lesson__module > p { + margin: 0.3rem 0 0.5rem; + font-size: 0.95rem; + color: var(--cn1-course-link-strong); + font-weight: 600; +} + +.cn1-course-lesson__module ol { + margin: 0; + padding-left: 1rem; +} + +.cn1-course-lesson__module li + li { + margin-top: 0.45rem; +} + +.cn1-course-lesson__module a { + color: var(--cn1-course-soft-text); + text-decoration: none; + font-size: 0.9rem; +} + +.cn1-course-lesson__module a.is-active { + color: var(--cn1-course-link-strong); + font-weight: 700; +} + +.cn1-course-lesson__content { + border: 1px solid var(--cn1-course-card-border); + border-radius: 14px; + padding: 1.15rem 1.2rem; + background: var(--cn1-course-card-bg); +} + +.cn1-course-lesson__content .cn1-embed { + margin-top: 1.2rem; +} + +.cn1-course-lesson__pager { + margin-top: 2rem; + padding-top: 1.2rem; + border-top: 1px solid var(--cn1-course-card-border); + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.7rem; +} + +.cn1-course-lesson__pager-link { + text-decoration: none; + border: 1px solid var(--cn1-course-card-border); + border-radius: 10px; + padding: 0.7rem 0.8rem; + color: var(--cn1-course-link-strong); + display: block; + background: rgba(8, 17, 55, 0.2); +} + +body.light .cn1-course-lesson__pager-link { + background: rgba(255, 255, 255, 0.75); +} + +.cn1-course-lesson__pager-link span { + display: block; + font-size: 0.75rem; + letter-spacing: 0.06em; + text-transform: uppercase; + color: var(--cn1-course-link); +} + +.cn1-course-lesson__pager-link strong { + display: block; + margin-top: 0.2rem; + line-height: 1.35; +} + +.cn1-course-lesson__pager-link--next { + text-align: right; +} + +@media (max-width: 1050px) { + .cn1-course-lesson__layout { + grid-template-columns: 1fr; + } + + .cn1-course-lesson__sidebar { + position: static; + max-height: none; + } +} + +@media (max-width: 760px) { + .cn1-course-overview__bar { + flex-direction: column; + align-items: flex-start; + } + + .cn1-course-lesson__pager { + grid-template-columns: 1fr; + } +} diff --git a/docs/website/assets/css/extended/cn1-crisp.css b/docs/website/assets/css/extended/cn1-crisp.css new file mode 100644 index 0000000000..d14267881b --- /dev/null +++ b/docs/website/assets/css/extended/cn1-crisp.css @@ -0,0 +1,95 @@ +.cn1-cookie-banner { + position: fixed; + left: 18px; + right: 18px; + bottom: 18px; + z-index: 120; + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 14px 16px; + background: #f2f5ff; + border: 1px solid rgba(28, 81, 255, 0.24); + border-radius: 10px; + box-shadow: 0 12px 32px rgba(9, 23, 64, 0.18); + color: #233462; + font-family: "Poppins", sans-serif; +} + +body.dark .cn1-cookie-banner { + background: #1f2b4a; + border-color: rgba(175, 193, 255, 0.28); + box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35); + color: #e7eeff; +} + +.cn1-cookie-banner p { + margin: 0; + font-size: 13px; + line-height: 1.4; +} + +.cn1-cookie-banner a { + color: #1c51ff; + text-decoration: underline; +} + +body.dark .cn1-cookie-banner a { + color: #afc1ff; +} + +.cn1-cookie-banner__actions { + display: inline-flex; + gap: 8px; + flex: 0 0 auto; +} + +.cn1-cookie-banner__actions button { + border: 1px solid rgba(28, 81, 255, 0.35); + border-radius: 8px; + background: #ffffff; + color: #1b2a55; + font-family: "Poppins", sans-serif; + font-size: 12px; + font-weight: 600; + padding: 8px 12px; + cursor: pointer; +} + +.cn1-cookie-banner__actions button[data-cn1-cookie-accept] { + background: #1c51ff; + border-color: #1c51ff; + color: #f5f8ff; +} + +body.dark .cn1-cookie-banner__actions button { + background: #162446; + border-color: rgba(175, 193, 255, 0.38); + color: #e7eeff; +} + +body.dark .cn1-cookie-banner__actions button[data-cn1-cookie-accept] { + background: #1d52ff; + border-color: #1d52ff; + color: #f5f8ff; +} + +@media (max-width: 820px) { + .cn1-cookie-banner { + flex-direction: column; + align-items: flex-start; + left: 12px; + right: 12px; + bottom: 12px; + padding: 12px; + } + + .cn1-cookie-banner__actions { + width: 100%; + } + + .cn1-cookie-banner__actions button { + flex: 1; + } +} diff --git a/docs/website/assets/css/extended/cn1-demo-page.css b/docs/website/assets/css/extended/cn1-demo-page.css new file mode 100644 index 0000000000..1786b637de --- /dev/null +++ b/docs/website/assets/css/extended/cn1-demo-page.css @@ -0,0 +1,219 @@ +.post-single--demo .post-header { + display: none; +} + +.post-single--demo .post-footer { + display: none; +} + +.post-single--demo { + --cn1-demo-bg: #eef2fb; + --cn1-demo-card: #ffffff; + --cn1-demo-border: #cfd8ee; + --cn1-demo-text: #172247; + --cn1-demo-muted: #4f5f8a; + --cn1-demo-accent: #1d52ff; + --cn1-demo-chip: #e9efff; +} + +body.dark .post-single--demo { + --cn1-demo-bg: #081447; + --cn1-demo-card: #142257; + --cn1-demo-border: #2f438f; + --cn1-demo-text: #eff4ff; + --cn1-demo-muted: #afc1ff; + --cn1-demo-accent: #8db2ff; + --cn1-demo-chip: rgba(255, 255, 255, 0.08); +} + +.post-single--demo { + background: var(--cn1-demo-bg); + border: 0; + border-radius: 0; + padding: 20px 0 0; + margin-top: 24px; +} + +.cn1-demo-top { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(420px, 52%); + gap: 24px; + align-items: start; +} + +.cn1-demo-page-block { + background: transparent; + border: 0; + border-radius: 0; + padding: 18px 16px; +} + +.cn1-demo-eyebrow { + margin: 0; + color: var(--cn1-demo-accent); + font-family: "Poppins", sans-serif; + font-size: 12px; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +.cn1-demo-page-block h2 { + margin: 6px 0 8px; + color: var(--cn1-demo-text); + font-family: "Poppins", sans-serif; + font-size: clamp(26px, 3vw, 38px); + line-height: 1.12; + font-weight: 600; +} + +.cn1-demo-summary { + margin: 0; + color: var(--cn1-demo-muted); + font-family: "Poppins", sans-serif; + font-size: 16px; + line-height: 1.4; +} + +.cn1-demo-actions { + margin-top: 14px; + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.cn1-demo-pill { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 8px 14px; + border-radius: 999px; + border: 1px solid var(--cn1-demo-accent); + background: var(--cn1-demo-accent); + color: #fff; + text-decoration: none; + font-family: "Poppins", sans-serif; + font-size: 13px; + font-weight: 600; + line-height: 1; +} + +.cn1-demo-pill--ghost { + background: var(--cn1-demo-chip); + color: var(--cn1-demo-text); +} + +.cn1-demo-carousel { + margin-top: 0; + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + grid-template-rows: auto auto; + gap: 10px 12px; + align-items: center; +} + +.cn1-demo-carousel__viewport { + overflow: hidden; + border: 1px solid var(--cn1-demo-border); + border-radius: 0; + background: #0a1a59; +} + +.cn1-demo-carousel__track { + display: flex; + transition: transform 240ms ease; +} + +.cn1-demo-carousel__slide { + min-width: 100%; + margin: 0; +} + +.cn1-demo-carousel__slide img { + width: 100%; + max-height: 640px; + object-fit: contain; + display: block; +} + +.cn1-demo-carousel__nav { + width: 40px; + height: 40px; + border-radius: 0; + border: 1px solid var(--cn1-demo-border); + background: var(--cn1-demo-card); + color: var(--cn1-demo-text); + cursor: pointer; +} + +.cn1-demo-carousel__dots { + grid-column: 1 / -1; + display: flex; + justify-content: center; + gap: 8px; +} + +.cn1-demo-carousel__dots button { + width: 10px; + height: 10px; + border-radius: 0; + border: 0; + background: color-mix(in srgb, var(--cn1-demo-accent) 35%, transparent); + cursor: pointer; +} + +.cn1-demo-carousel__dots button[aria-current="true"] { + background: var(--cn1-demo-accent); +} + +.post-single--demo .cn1-demo-details { + margin-top: 16px; + background: var(--cn1-demo-card); + border: 1px solid var(--cn1-demo-border); + border-radius: 0; + padding: 26px 24px; +} + +.post-single--demo .cn1-demo-details h2:first-child, +.post-single--demo .cn1-demo-details h2#screenshots { + display: none; +} + +.post-single--demo .cn1-demo-details > p:first-child { + display: none; +} + +.post-single--demo .cn1-demo-details > p > img { + display: none; +} + +.post-single--demo .cn1-demo-details > ul:first-of-type { + display: none; +} + +.post-single--demo .cn1-demo-details img { + border-radius: 0; + border: 1px solid var(--cn1-demo-border); +} + +@media (max-width: 900px) { + .post-single--demo { + padding: 12px 0 0; + } + + .cn1-demo-top { + grid-template-columns: 1fr; + } + + .cn1-demo-carousel { + grid-template-columns: 1fr; + } + + .cn1-demo-carousel__nav { + display: none; + } + + .post-single--demo .cn1-demo-details { + padding: 18px 16px; + } +} diff --git a/docs/website/assets/css/extended/cn1-demos.css b/docs/website/assets/css/extended/cn1-demos.css new file mode 100644 index 0000000000..7754444ff5 --- /dev/null +++ b/docs/website/assets/css/extended/cn1-demos.css @@ -0,0 +1,171 @@ +.cn1-demos-page { + --cn1-demos-bg: #eef1f8; + --cn1-demos-card: #ffffff; + --cn1-demos-border: #cfd8ee; + --cn1-demos-text: #172247; + --cn1-demos-muted: #4f5f8a; + --cn1-demos-accent: #1d52ff; + --cn1-demos-chip: #e9efff; + background: var(--cn1-demos-bg); + color: var(--cn1-demos-text); + width: 100vw; + margin-left: calc(50% - 50vw); + margin-right: calc(50% - 50vw); + padding: 28px 0 64px; +} + +body.dark .cn1-demos-page { + --cn1-demos-bg: #071246; + --cn1-demos-card: #142257; + --cn1-demos-border: #2f438f; + --cn1-demos-text: #eff4ff; + --cn1-demos-muted: #afc1ff; + --cn1-demos-accent: #8db2ff; + --cn1-demos-chip: rgba(255, 255, 255, 0.08); +} + +.cn1-demos-hero, +.cn1-demos-grid { + max-width: 1320px; + margin: 0 auto; + padding: 0 32px; +} + +.cn1-demos-eyebrow { + margin: 0; + color: var(--cn1-demos-accent); + font-family: "Poppins", sans-serif; + font-size: 14px; + letter-spacing: 0.1em; + text-transform: uppercase; + font-weight: 700; +} + +.cn1-demos-hero h1 { + margin: 8px 0 10px; + font-family: "Poppins", sans-serif; + font-size: clamp(32px, 4vw, 54px); + line-height: 1.05; + color: var(--cn1-demos-text); +} + +.cn1-demos-subtitle { + margin: 0; + font-family: "Poppins", sans-serif; + color: var(--cn1-demos-muted); + font-size: 17px; + font-weight: 500; +} + +.cn1-demos-grid { + margin-top: 28px; + display: grid; + gap: 20px; + grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); +} + +.cn1-demo-card { + display: grid; + grid-template-rows: auto 1fr; + gap: 0; + border: 1px solid var(--cn1-demos-border); + border-radius: 14px; + overflow: hidden; + background: var(--cn1-demos-card); + box-shadow: 0 10px 24px rgba(8, 16, 45, 0.08); + transition: transform 140ms ease, box-shadow 140ms ease, border-color 140ms ease; +} + +.cn1-demo-card:hover { + transform: translateY(-3px); + box-shadow: 0 16px 32px rgba(8, 16, 45, 0.14); + border-color: color-mix(in srgb, var(--cn1-demos-accent) 45%, var(--cn1-demos-border)); +} + +.cn1-demo-card__thumb { + display: block; + background: linear-gradient(145deg, #2a5fff 0%, #1f4ce0 100%); +} + +.cn1-demo-card__thumb img { + width: 100%; + aspect-ratio: 16 / 10; + object-fit: cover; + mix-blend-mode: screen; +} + +body.dark .cn1-demo-card__thumb img { + mix-blend-mode: normal; +} + +.cn1-demo-card__body { + padding: 20px 24px; + display: flex; + flex-direction: column; +} + +.cn1-demo-card__body h2 { + margin: 0; + font-family: "Poppins", sans-serif; + font-size: 28px; + font-weight: 600; + line-height: 1.15; +} + +.cn1-demo-card__body h2 a { + color: var(--cn1-demos-text); + text-decoration: none; +} + +.cn1-demo-card__body h2 a:hover { + color: var(--cn1-demos-accent); +} + +.cn1-demo-card__body p { + margin: 12px 0 0; + color: var(--cn1-demos-muted); + font-family: "Poppins", sans-serif; + font-size: 15px; + line-height: 1.45; +} + +.cn1-demo-card__actions { + margin-top: 16px; + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: auto; + padding-top: 10px; +} + +.cn1-demo-pill { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 8px 14px; + border-radius: 999px; + border: 1px solid var(--cn1-demos-accent); + background: var(--cn1-demos-accent); + color: #fff; + text-decoration: none; + font-family: "Poppins", sans-serif; + font-size: 13px; + font-weight: 600; + line-height: 1; +} + +.cn1-demo-pill--ghost { + background: var(--cn1-demos-chip); + color: var(--cn1-demos-text); +} + +@media (max-width: 900px) { + .cn1-demos-hero, + .cn1-demos-grid { + padding: 0 16px; + } + + .cn1-demos-grid { + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + } +} diff --git a/docs/website/assets/css/extended/cn1-developing.css b/docs/website/assets/css/extended/cn1-developing.css new file mode 100644 index 0000000000..4a26e742cb --- /dev/null +++ b/docs/website/assets/css/extended/cn1-developing.css @@ -0,0 +1,164 @@ +.post-header--with-hero { + display: grid; + grid-template-columns: minmax(0, 1fr) clamp(240px, 30vw, 420px); + align-items: center; + gap: 28px; +} + +.post-header--with-hero .post-header__content { + min-width: 0; +} + +.post-header--with-hero .post-header__hero img { + width: 100%; + height: auto; + display: block; +} + +.post-single--developing-in-codename-one .post-content { + padding: 6px 0 0; +} + +.post-single--developing-in-codename-one .post-content > h2 { + font-size: clamp(28px, 2.4vw, 34px); + margin-top: 8px; + margin-bottom: 16px; + clear: both; +} + +.post-single--developing-in-codename-one .post-content > h2 + p + ul { + list-style: none; + padding: 0; + margin: 0 0 30px; + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px; + margin-right: clamp(280px, 36vw, 450px); +} + +.post-single--developing-in-codename-one .post-content > h2 + p + ul li { + margin: 0; +} + +.post-single--developing-in-codename-one .post-content > h2 + p + ul a { + display: block; + padding: 14px 16px; + border: 1px solid rgba(29, 82, 255, 0.35); + border-radius: 12px; + background: rgba(255, 255, 255, 0.72); + text-decoration: none; + box-shadow: 0 6px 16px rgba(17, 42, 116, 0.08); + transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease; +} + +.post-single--developing-in-codename-one .post-content > h2 + p + ul a:hover { + transform: translateY(-1px); + border-color: rgba(29, 82, 255, 0.65); + box-shadow: 0 10px 20px rgba(17, 42, 116, 0.12); +} + +.post-single--developing-in-codename-one .post-content > h2:nth-of-type(1) + p, +.post-single--developing-in-codename-one .post-content > h2:nth-of-type(2) + p + p { + width: clamp(260px, 32vw, 420px); + float: right; + margin: 4px 0 18px 24px; +} + +.post-single--developing-in-codename-one .post-content > h2:nth-of-type(1) + p img, +.post-single--developing-in-codename-one .post-content > h2:nth-of-type(2) + p + p img { + display: block; + width: 100%; + height: auto; +} + +.post-single--developing-in-codename-one .post-content img[src*="Group-2197.svg"] { + display: block; + margin: 8px auto 24px; + max-width: min(100%, 520px); +} + +.post-single--developing-in-codename-one .post-content > h2:nth-of-type(2) + p + p + ul { + list-style: none; + padding: 0; + margin: 0 0 28px; + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px; + margin-right: clamp(280px, 36vw, 450px); +} + +.post-single--developing-in-codename-one .post-content > h2:nth-of-type(2) + p + p + ul li { + margin: 0; + padding: 14px 16px; + border: 1px solid rgba(29, 82, 255, 0.22); + border-radius: 12px; + background: rgba(255, 255, 255, 0.72); +} + +.post-single--developing-in-codename-one .post-content > h2:nth-of-type(2) + p + p + ul li p { + margin: 0; +} + +.post-single--developing-in-codename-one .post-content > h2:nth-of-type(2) + p + p + ul li strong a { + text-decoration: none; + font-size: 20px; + line-height: 1.25; + color: inherit; +} + +.post-single--developing-in-codename-one .post-content > h2:nth-of-type(2) + p + p + ul li strong { + display: block; + margin-bottom: 8px; +} + +.post-single--developing-in-codename-one .post-content > h2:nth-of-type(2) + p + p + ul::after, +.post-single--developing-in-codename-one .post-content > h2 + p + ul::after { + content: ""; + display: block; + clear: both; +} + +body.dark .post-single--developing-in-codename-one .post-content { + background: transparent; + border-color: transparent; +} + +body.dark .post-single--developing-in-codename-one .post-content > h2 + p + ul a, +body.dark .post-single--developing-in-codename-one .post-content > h2:nth-of-type(2) + p + p + ul li { + background: rgba(25, 36, 81, 0.3); + border-color: rgba(168, 190, 255, 0.3); + box-shadow: none; +} + +body.dark .post-single--developing-in-codename-one .post-content > h2 + p + ul a:hover { + border-color: rgba(168, 190, 255, 0.6); +} + +@media (max-width: 900px) { + .post-header--with-hero { + grid-template-columns: 1fr; + gap: 16px; + } + + .post-header--with-hero .post-header__hero img { + max-width: 320px; + margin: 0 auto; + } + + .post-single--developing-in-codename-one .post-content > h2 + p + ul { + grid-template-columns: 1fr; + margin-right: 0; + } + + .post-single--developing-in-codename-one .post-content > h2:nth-of-type(1) + p, + .post-single--developing-in-codename-one .post-content > h2:nth-of-type(2) + p + p { + float: none; + width: 100%; + margin: 16px auto; + } + + .post-single--developing-in-codename-one .post-content > h2:nth-of-type(2) + p + p + ul { + grid-template-columns: 1fr; + margin-right: 0; + } +} diff --git a/docs/website/assets/css/extended/cn1-development-environment.css b/docs/website/assets/css/extended/cn1-development-environment.css new file mode 100644 index 0000000000..d5ca0adf32 --- /dev/null +++ b/docs/website/assets/css/extended/cn1-development-environment.css @@ -0,0 +1,225 @@ +.post-single--development-environment .post-content { + --cn1-dev-blue: #1d52ff; + --cn1-dev-soft: rgba(29, 82, 255, 0.08); + --cn1-dev-soft-border: rgba(29, 82, 255, 0.24); + --cn1-dev-surface: rgba(29, 82, 255, 0.03); +} + +body.dark .post-single--development-environment .post-content { + --cn1-dev-blue: #afc1ff; + --cn1-dev-soft: rgba(175, 193, 255, 0.14); + --cn1-dev-soft-border: rgba(175, 193, 255, 0.3); + --cn1-dev-surface: rgba(175, 193, 255, 0.07); +} + +.post-single--development-environment .post-content > p:first-of-type { + font-size: 1.1rem; + line-height: 1.72; + font-weight: 500; + margin-bottom: 1rem; +} + +.post-single--development-environment .post-content img[src*="Group-2326.svg"] { + float: right; + width: min(470px, 46%); + margin: 0.2rem 0 1rem 1.6rem; +} + +.post-single--development-environment .post-content > h2 { + clear: both; + margin-top: 2.1rem; + margin-bottom: 0.85rem; + padding: 0.58rem 0.95rem; + border-left: 4px solid var(--cn1-dev-blue); + background: var(--cn1-dev-soft); + color: var(--cn1-dev-blue); +} + +.post-single--development-environment .post-content > h3 { + margin-top: 1.2rem; + margin-bottom: 0.45rem; + color: var(--cn1-dev-blue); +} + +.post-single--development-environment .post-content .cn1-dev-value-grid { + display: grid; + grid-template-columns: repeat(3, minmax(180px, 1fr)); + gap: 0.8rem; + margin: 0.35rem 0 1.35rem; +} + +.post-single--development-environment .post-content .cn1-dev-value-item { + background: var(--cn1-dev-surface); + border: 1px solid var(--cn1-dev-soft-border); + padding: 0.9rem; +} + +.post-single--development-environment .post-content .cn1-dev-value-item svg { + width: 1.35rem; + height: 1.35rem; + color: var(--cn1-dev-blue); + stroke: currentColor; + fill: none; + stroke-width: 1.7; + stroke-linecap: round; + stroke-linejoin: round; + display: block; +} + +.post-single--development-environment .post-content .cn1-dev-value-item h3 { + margin: 0.5rem 0 0.35rem; + font-size: 1.06rem; + color: var(--cn1-dev-blue); +} + +.post-single--development-environment .post-content .cn1-dev-value-item p { + margin: 0; + font-size: 0.94rem; + line-height: 1.55; +} + +.post-single--development-environment .post-content .cn1-ide-strip { + display: grid; + grid-template-columns: repeat(4, minmax(150px, 1fr)); + gap: 0.65rem; + margin: 0.35rem 0 1.4rem; +} + +.post-single--development-environment .post-content .cn1-ide-item { + display: flex; + align-items: center; + justify-content: center; + gap: 0.45rem; + min-height: 56px; + padding: 0.45rem 0.7rem; + background: var(--cn1-dev-surface); + border: 1px solid var(--cn1-dev-soft-border); +} + +.post-single--development-environment .post-content .cn1-ide-item img { + width: 26px; + height: 26px; + object-fit: contain; +} + +.post-single--development-environment .post-content .cn1-ide-item i { + color: var(--cn1-dev-blue); + font-size: 1.2rem; +} + +.post-single--development-environment .post-content .cn1-ide-item span { + color: var(--cn1-dev-blue); + font-weight: 600; + font-size: 0.94rem; +} + +.post-single--development-environment .post-content .cn1-flow-stack { + display: grid; + gap: 0.85rem; + margin: 0.35rem 0 1.35rem; +} + +.post-single--development-environment .post-content .cn1-step-card { + display: grid; + grid-template-columns: minmax(220px, 0.95fr) minmax(320px, 1.6fr); + gap: 0.95rem; + align-items: center; + background: var(--cn1-dev-surface); + border: 1px solid var(--cn1-dev-soft-border); + padding: 0.8rem; +} + +.post-single--development-environment .post-content .cn1-step-card--reverse .cn1-step-copy { + order: 2; +} + +.post-single--development-environment .post-content .cn1-step-card--reverse .cn1-step-media { + order: 1; +} + +.post-single--development-environment .post-content .cn1-step-kicker { + display: inline-block; + margin-bottom: 0.35rem; + color: var(--cn1-dev-blue); + font-weight: 700; + font-size: 0.78rem; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.post-single--development-environment .post-content .cn1-step-copy h3 { + margin: 0 0 0.38rem; + color: var(--cn1-dev-blue); + font-size: 1.22rem; +} + +.post-single--development-environment .post-content .cn1-step-copy p { + margin: 0; + line-height: 1.58; +} + +.post-single--development-environment .post-content .cn1-step-media img { + margin: 0; + width: 100%; + display: block; +} + +.post-single--development-environment .post-content .cn1-highlight-pair { + display: grid; + grid-template-columns: minmax(220px, 0.9fr) minmax(340px, 1.6fr); + gap: 1rem; + align-items: center; + margin: 0.2rem 0 1rem; + padding: 0.8rem 0.95rem; + background: var(--cn1-dev-soft); + border-left: 4px solid var(--cn1-dev-blue); +} + +.post-single--development-environment .post-content .cn1-highlight-copy h4 { + margin: 0 0 0.4rem; + color: var(--cn1-dev-blue); + font-size: 1.16rem; +} + +.post-single--development-environment .post-content .cn1-highlight-copy p { + margin: 0; +} + +.post-single--development-environment .post-content .cn1-highlight-media img { + margin: 0; + width: 100%; + display: block; +} + +.post-single--development-environment .post-content::after { + content: ""; + display: block; + clear: both; +} + +@media (max-width: 980px) { + .post-single--development-environment .post-content img[src*="Group-2326.svg"] { + float: none; + width: min(440px, 100%); + margin: 0.45rem auto 1rem; + display: block; + } + + .post-single--development-environment .post-content .cn1-dev-value-grid { + grid-template-columns: 1fr; + } + + .post-single--development-environment .post-content .cn1-ide-strip { + grid-template-columns: repeat(2, minmax(150px, 1fr)); + } + + .post-single--development-environment .post-content .cn1-step-card, + .post-single--development-environment .post-content .cn1-highlight-pair { + grid-template-columns: 1fr; + } + + .post-single--development-environment .post-content .cn1-step-card--reverse .cn1-step-copy, + .post-single--development-environment .post-content .cn1-step-card--reverse .cn1-step-media { + order: initial; + } +} diff --git a/docs/website/assets/css/extended/cn1-faq.css b/docs/website/assets/css/extended/cn1-faq.css new file mode 100644 index 0000000000..5123e75a9e --- /dev/null +++ b/docs/website/assets/css/extended/cn1-faq.css @@ -0,0 +1,91 @@ +.post-single--faq .post-header { + margin-bottom: 1.25rem; + padding: 1.25rem 1.25rem 1.1rem; + border: 1px solid rgba(29, 82, 255, 0.25); + border-radius: 14px; + background: linear-gradient(140deg, rgba(29, 82, 255, 0.12), rgba(29, 82, 255, 0.02)); +} + +body.dark .post-single--faq .post-header { + border-color: rgba(175, 193, 255, 0.25); + background: linear-gradient(140deg, rgba(36, 66, 158, 0.3), rgba(7, 20, 60, 0.35)); +} + +.post-single--faq .post-content > h2 { + margin-top: 2rem; + margin-bottom: 0.6rem; + padding: 0.7rem 0.9rem; + border-left: 4px solid #1d52ff; + border-radius: 10px; + background: rgba(29, 82, 255, 0.08); +} + +body.dark .post-single--faq .post-content > h2 { + border-left-color: #afc1ff; + background: rgba(175, 193, 255, 0.12); +} + +.post-single--faq .post-content > h3 { + margin-top: 1.25rem; + margin-bottom: 0.35rem; + font-size: 1.2rem; +} + +.post-single--faq .post-content > h3::before { + content: "Q"; + display: inline-flex; + width: 1.35rem; + height: 1.35rem; + align-items: center; + justify-content: center; + margin-right: 0.5rem; + border-radius: 50%; + font-size: 0.8rem; + font-weight: 700; + color: #f5f8ff; + background: #1d52ff; + vertical-align: 0.05rem; +} + +body.dark .post-single--faq .post-content > h3::before { + color: #061033; + background: #afc1ff; +} + +.post-single--faq .post-content > p, +.post-single--faq .post-content > ul { + margin-left: 1.9rem; +} + +.post-single--faq .post-content > blockquote { + margin: 0.9rem 0 1.2rem; + border-left: 4px solid #1d52ff; + border-radius: 10px; + background: rgba(29, 82, 255, 0.06); + padding: 0.8rem 1rem; +} + +body.dark .post-single--faq .post-content > blockquote { + border-left-color: #afc1ff; + background: rgba(175, 193, 255, 0.14); +} + +.post-single--faq .post-content > ul:last-child { + margin-left: 0; + padding: 1rem; + border: 1px solid rgba(29, 82, 255, 0.2); + border-radius: 12px; + background: rgba(29, 82, 255, 0.05); +} + +body.dark .post-single--faq .post-content > ul:last-child { + border-color: rgba(175, 193, 255, 0.35); + background: rgba(175, 193, 255, 0.08); +} + +@media (max-width: 900px) { + .post-single--faq .post-content > p, + .post-single--faq .post-content > ul { + margin-left: 0.6rem; + } +} diff --git a/docs/website/assets/css/extended/cn1-getting-started.css b/docs/website/assets/css/extended/cn1-getting-started.css new file mode 100644 index 0000000000..1b0043842f --- /dev/null +++ b/docs/website/assets/css/extended/cn1-getting-started.css @@ -0,0 +1,310 @@ +.cn1-gs-page { + --cn1-gs-bg: #dfe2ea; + --cn1-gs-card-bg: #f6f7fa; + --cn1-gs-card-border: #d5d9e1; + --cn1-gs-text: #0e1b49; + --cn1-gs-muted: #4d5160; + --cn1-gs-crumb: #9ba2b5; + --cn1-gs-accent: #2c57e6; + --cn1-gs-separator: #e1e3e8; + --cn1-gs-cta-bg: #a6cd2b; + --cn1-gs-cta-bg-hover: #b6dd36; + --cn1-gs-cta-text: #34403b; + --cn1-gs-media-bg: #ffffff; + background: #dfe2ea; + color: #0e1b49; + padding: 22px 0 84px; + width: 100vw; + margin-left: calc(50% - 50vw); + margin-right: calc(50% - 50vw); +} + +body.dark .cn1-gs-page { + --cn1-gs-bg: #0a1438; + --cn1-gs-card-bg: #131e4b; + --cn1-gs-card-border: #2a3a77; + --cn1-gs-text: #e7ecff; + --cn1-gs-muted: #c2cdee; + --cn1-gs-crumb: #9cb2eb; + --cn1-gs-accent: #7fa5ff; + --cn1-gs-separator: #2a3a77; + --cn1-gs-cta-bg: #9dc62a; + --cn1-gs-cta-bg-hover: #b0d83e; + --cn1-gs-cta-text: #1f2d52; + --cn1-gs-media-bg: #0f1a46; +} + +.cn1-gs-page { + background: var(--cn1-gs-bg); + color: var(--cn1-gs-text); +} + +.cn1-gs-hero { + max-width: 1400px; + margin: 0 auto; + display: grid; + grid-template-columns: 1fr 1fr; + align-items: center; + gap: 26px; + padding: 48px 72px 44px; +} + +.cn1-gs-breadcrumbs { + display: inline-flex; + align-items: center; + gap: 14px; + margin-bottom: 20px; +} + +.cn1-gs-breadcrumbs a, +.cn1-gs-breadcrumbs span { + color: var(--cn1-gs-crumb); + font-size: 14px; + font-weight: 500; +} + +.cn1-gs-breadcrumbs a:hover { + color: var(--cn1-gs-accent); +} + +.cn1-gs-hero h1 { + margin: 0; + color: var(--cn1-gs-accent); + font-family: "Poppins", sans-serif; + font-size: 40px; + line-height: 1.05; + font-weight: 600; +} + +.cn1-gs-hero p { + margin-top: 14px; + color: var(--cn1-gs-muted); + font-family: "Poppins", sans-serif; + font-size: 14px; + font-weight: 600; + line-height: 1.2; +} + +.cn1-gs-hero__art { + display: flex; + justify-content: center; +} + +.cn1-gs-hero__art img { + width: 100%; + max-width: 520px; + height: auto; +} + +.cn1-gs-step-card { + max-width: 1580px; + margin: 0 auto 44px; + background: var(--cn1-gs-card-bg); + border: 1px solid var(--cn1-gs-card-border); + border-radius: 10px; + padding: 56px 72px 48px; +} + +.cn1-gs-step-label { + margin: 0 0 12px; + color: var(--cn1-gs-accent); + font-family: "Poppins", sans-serif; + font-size: 13px; + font-weight: 700; + letter-spacing: 0.02em; +} + +.cn1-gs-step-card h2 { + margin: 0; + color: var(--cn1-gs-text); + font-family: "Poppins", sans-serif; + font-size: 28px; + font-weight: 600; + line-height: 1.14; + padding-bottom: 20px; + border-bottom: 2px solid var(--cn1-gs-separator); +} + +.cn1-gs-step-row { + display: grid; + grid-template-columns: 1fr auto; + align-items: center; + gap: 28px; + padding: 24px 0 30px; +} + +.cn1-gs-step-row p { + margin: 0; + color: var(--cn1-gs-muted); + font-family: "Poppins", sans-serif; + font-size: 15px; + line-height: 1.45; + font-weight: 500; +} + +.cn1-gs-cta { + display: inline-block; + background: var(--cn1-gs-cta-bg); + color: var(--cn1-gs-cta-text); + padding: 12px 30px; + border-radius: 8px; + font-family: "Poppins", sans-serif; + font-size: 15px; + font-weight: 600; + text-decoration: none; + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.15); +} + +.cn1-gs-cta:hover { + background: var(--cn1-gs-cta-bg-hover); +} + +.cn1-gs-video { + border-radius: 8px; + overflow: hidden; +} + +.cn1-gs-video iframe { + width: 100%; + aspect-ratio: 16 / 9; + border: 0; + display: block; +} + +.cn1-gs-build-grid { + display: grid; + grid-template-columns: 0.9fr 1fr 1fr; + gap: 36px; + padding-top: 30px; + align-items: start; +} + +.cn1-gs-build-copy p { + margin: 0; + color: var(--cn1-gs-text); + font-family: "Poppins", sans-serif; + font-size: 22px; + line-height: 1.28; + font-weight: 500; +} + +.cn1-gs-resource-card img { + width: 100%; + max-height: 175px; + object-fit: contain; + background: var(--cn1-gs-media-bg); + border-radius: 8px; + display: block; +} + +.cn1-gs-resource-card p { + margin: 16px 0 0; + color: var(--cn1-gs-muted); + font-family: "Poppins", sans-serif; + font-size: 14px; + line-height: 1.45; + font-weight: 500; +} + +.cn1-gs-resource-card > a, +.cn1-gs-links a { + margin-top: 14px; + display: inline-flex; + align-items: center; + gap: 12px; + color: var(--cn1-gs-muted); + font-family: "Poppins", sans-serif; + font-size: 14px; + font-weight: 600; + text-decoration: none; + border-top: 2px solid var(--cn1-gs-separator); + padding-top: 14px; +} + +.cn1-gs-resource-card > a:hover, +.cn1-gs-links a:hover { + color: var(--cn1-gs-accent); +} + +.cn1-gs-links { + display: grid; + gap: 12px; +} + +@media (max-width: 1200px) { + .cn1-gs-hero { + grid-template-columns: 1fr; + padding: 34px 22px 24px; + } + + .cn1-gs-step-card { + margin: 0 18px 26px; + padding: 34px 24px; + } + + .cn1-gs-hero h1 { + font-size: 34px; + } + + .cn1-gs-hero p { + font-size: 16px; + } + + .cn1-gs-breadcrumbs a, + .cn1-gs-breadcrumbs span { + font-size: 18px; + } + + .cn1-gs-step-label { + font-size: 14px; + } + + .cn1-gs-step-card h2 { + font-size: 26px; + padding-bottom: 16px; + } + + .cn1-gs-step-row { + grid-template-columns: 1fr; + gap: 20px; + padding: 24px 0 28px; + } + + .cn1-gs-step-row p { + font-size: 16px; + } + + .cn1-gs-cta { + font-size: 16px; + padding: 12px 20px; + } + + .cn1-gs-build-grid { + grid-template-columns: 1fr; + gap: 28px; + padding-top: 24px; + } + + .cn1-gs-build-copy p { + font-size: 22px; + } + + .cn1-gs-resource-card p { + font-size: 15px; + } + + .cn1-gs-resource-card > a, + .cn1-gs-links a { + font-size: 15px; + } + + .cn1-gs-hero__art img { + max-width: 360px; + } +} + +@media (max-width: 768px) { + .cn1-gs-hero__art img { + max-width: 280px; + } +} diff --git a/docs/website/assets/css/extended/cn1-home.css b/docs/website/assets/css/extended/cn1-home.css new file mode 100644 index 0000000000..ec03306f2e --- /dev/null +++ b/docs/website/assets/css/extended/cn1-home.css @@ -0,0 +1,1987 @@ +:root, +body { + --cn1-home-bg: #f1f4fc; + --cn1-home-text: #0d1847; + --cn1-home-muted: #55607f; + --cn1-home-header-bg: #eef1f7; + --cn1-home-header-border: rgba(17, 33, 84, 0.1); + --cn1-home-strip-bg: #1d5ff0; + --cn1-home-strip-text: #eef4ff; + --cn1-home-nav-text: #0d1847; + --cn1-home-submenu-bg: #dbe3f7; + --cn1-home-submenu-border: #c3cde6; + --cn1-home-submenu-text: #0d1847; + --cn1-home-dashboard-border: #2f56d8; + --cn1-home-card-bg: #e7ecfb; + --cn1-home-card-border: #2b66ea; + --cn1-home-card-text: #1b274e; + --cn1-home-section-title: #2856dc; + --cn1-home-footer-bg: #f1f4fc; + --cn1-home-footer-text: #55607f; +} + +body.cn1-homepage { + --cn1-home-bg: #f1f4fc; + --cn1-home-text: #0d1847; + --cn1-home-muted: #55607f; + --cn1-home-header-bg: #eef1f7; + --cn1-home-header-border: rgba(17, 33, 84, 0.1); + --cn1-home-strip-bg: #1d5ff0; + --cn1-home-strip-text: #eef4ff; + --cn1-home-nav-text: #0d1847; + --cn1-home-submenu-bg: #dbe3f7; + --cn1-home-submenu-border: #c3cde6; + --cn1-home-submenu-text: #0d1847; + --cn1-home-dashboard-border: #2f56d8; + --cn1-home-card-bg: #e7ecfb; + --cn1-home-card-border: #2b66ea; + --cn1-home-card-text: #1b274e; + --cn1-home-section-title: #2856dc; + --cn1-home-footer-bg: #f1f4fc; + --cn1-home-footer-text: #55607f; +} + +body.dark, +body.dark.cn1-homepage { + --cn1-home-bg: #020d44; + --cn1-home-text: #ffffff; + --cn1-home-muted: #dbe4ff; + --cn1-home-header-bg: #020d44; + --cn1-home-header-border: rgba(255, 255, 255, 0.08); + --cn1-home-strip-bg: #1062df; + --cn1-home-strip-text: #e8f0ff; + --cn1-home-nav-text: #ffffff; + --cn1-home-submenu-bg: #c8cedd; + --cn1-home-submenu-border: #b1b9cc; + --cn1-home-submenu-text: #0d1847; + --cn1-home-dashboard-border: #d9e3ff; + --cn1-home-card-bg: #374261; + --cn1-home-card-border: #1f6dff; + --cn1-home-card-text: #dbe4ff; + --cn1-home-section-title: #a8beff; + --cn1-home-footer-bg: #020d44; + --cn1-home-footer-text: #9eb5ff; +} + +.cn1-homepage { + background: var(--cn1-home-bg); + color: var(--cn1-home-text); + font-family: "Poppins", sans-serif; +} + +.cn1-homepage .main { + max-width: 100%; + padding: 0; +} + +.cn1-homepage .header { + position: sticky; + top: 0; + z-index: 50; + background: var(--cn1-home-header-bg); + border-bottom: 1px solid var(--cn1-home-header-border); + padding-top: 40px; +} + +.cn1-homepage .header::before { + content: "Open Source & Free"; + position: fixed; + top: 0; + left: 0; + right: 0; + height: 40px; + background: var(--cn1-home-strip-bg); + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + font-weight: 700; + color: var(--cn1-home-strip-text); +} + +.cn1-homepage .nav { + display: flex; + flex-wrap: nowrap; + align-items: center; + max-width: 1320px; + min-height: 84px; + line-height: 84px; +} + +.cn1-homepage .logo a { + position: relative; + color: #fff; + font-size: 0; + letter-spacing: 0; + font-weight: 700; + padding-left: 0; + display: flex; + align-items: center; +} + +.cn1-homepage .logo a::before { + content: none; +} + +.cn1-homepage .logo a img, +.cn1-homepage .logo a svg { + height: 34px; + width: auto; + transform: none; + margin-inline-end: 0; + border-radius: 0; +} + +.cn1-brand-logo { + height: 34px; + width: auto; + display: block; +} + +body:not(.dark) .cn1-brand-logo { + /* Make the white header logo visible on light header backgrounds */ + filter: brightness(0) saturate(100%); +} + +.cn1-homepage #menu a { + color: var(--cn1-home-nav-text); + font-size: 18px; + font-weight: 700; + letter-spacing: 0.01em; +} + +.cn1-homepage #menu { + display: flex; + align-items: center; + gap: 34px; + margin: 0; + margin-inline-start: auto; + overflow-x: visible; + scrollbar-width: none; +} + +.cn1-homepage #menu::-webkit-scrollbar { + display: none; +} + +.cn1-homepage #menu > li { + position: relative; +} + +.cn1-homepage #menu > li + li { + margin-inline-start: 0; +} + +.cn1-homepage #menu > li > a, +.cn1-homepage #menu > li > details > summary { + color: var(--cn1-home-nav-text); + font-size: 18px; + font-weight: 700; + letter-spacing: 0.01em; + text-decoration: none; + line-height: 84px; +} + +.cn1-homepage #menu > li > details > summary { + list-style: none; + cursor: pointer; +} + +.cn1-homepage #menu > li > details > summary::-webkit-details-marker { + display: none; +} + +.cn1-homepage #menu > li > details > summary::after { + content: " ▾"; + font-size: 0.9em; +} + +.cn1-homepage #menu > li > details[open] > summary { + color: #d4e1ff; +} + +.cn1-homepage #menu .sub-menu { + list-style: none; + margin: 0; + padding: 0; + min-width: 300px; + background: var(--cn1-home-submenu-bg); + border-radius: 0 0 14px 14px; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.24); + position: absolute; + top: calc(100% - 2px); + left: 0; + z-index: 80; +} + +.cn1-homepage #menu .sub-menu li + li { + border-top: 1px solid var(--cn1-home-submenu-border); +} + +.cn1-homepage #menu .sub-menu a { + color: var(--cn1-home-submenu-text); + padding: 22px 26px; + line-height: 1.25; + font-size: 17px; + font-weight: 600; + display: block; +} + +.cn1-homepage .cn1-nav-toggle { + display: none; +} + +.cn1-homepage .cn1-nav-toggle-btn { + display: none; +} + +.cn1-homepage .cn1-nav-links { + margin-inline-start: 0; +} + +.cn1-homepage .cn1-dashboard-link { + border: 2px solid var(--cn1-home-dashboard-border); + border-radius: 12px; + padding: 0 28px; + line-height: 46px; + margin-top: 18px; + color: var(--cn1-home-nav-text); + font-size: 18px; + font-weight: 700; + text-decoration: none; + margin-inline-start: 24px; +} + +.cn1-header { + position: sticky; + top: 0; + z-index: 50; + background: var(--cn1-home-header-bg); + border-bottom: 1px solid var(--cn1-home-header-border); + padding-top: 40px; +} + +.cn1-header::before { + content: "Open Source & Free"; + position: fixed; + top: 0; + left: 0; + right: 0; + height: 40px; + background: var(--cn1-home-strip-bg); + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + font-weight: 700; + color: var(--cn1-home-strip-text); +} + +.cn1-header .nav { + display: flex; + flex-wrap: nowrap; + align-items: center; + max-width: 1320px; + min-height: 84px; + line-height: 84px; + transition: min-height 180ms ease, line-height 180ms ease; +} + +.cn1-header .logo a { + position: relative; + color: #fff; + font-size: 0; + letter-spacing: 0; + font-weight: 700; + padding-left: 0; + display: flex; + align-items: center; +} + +.cn1-header .logo a img, +.cn1-header .logo a svg { + height: 34px; + width: auto; + transform: none; + margin-inline-end: 0; + border-radius: 0; + transition: height 180ms ease; +} + +.cn1-header #menu { + display: flex; + align-items: center; + gap: 34px; + margin: 0; + margin-inline-start: auto; + overflow-x: visible; + scrollbar-width: none; +} + +.cn1-header #menu > li { + position: relative; +} + +.cn1-header #menu > li + li { + margin-inline-start: 0; +} + +.cn1-header #menu > li > a, +.cn1-header #menu > li > .cn1-menu-trigger { + color: var(--cn1-home-nav-text); + font-size: 18px; + font-weight: 700; + letter-spacing: 0.01em; + text-decoration: none; + line-height: 84px; +} + +.cn1-header #menu > li > .cn1-menu-trigger { + appearance: none; + background: none; + border: 0; + margin: 0; + padding: 0; + font: inherit; + font-size: 18px; + color: var(--cn1-home-nav-text); + cursor: pointer; +} + +.cn1-header #menu > li.has-children > .cn1-menu-trigger::after { + content: " ▾"; + font-size: 0.9em; +} + +.cn1-header #menu .sub-menu { + display: none; + list-style: none; + margin: 0; + padding: 0; + min-width: 300px; + background: var(--cn1-home-submenu-bg); + border-radius: 0 0 14px 14px; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.24); + position: absolute; + top: calc(100% - 2px); + left: 0; + z-index: 80; +} + +.cn1-header #menu .sub-menu li + li { + border-top: 1px solid var(--cn1-home-submenu-border); +} + +.cn1-header #menu .sub-menu a { + color: var(--cn1-home-submenu-text); + padding: 22px 26px; + line-height: 1.25; + font-size: 17px; + font-weight: 600; + display: block; +} + +.cn1-header #menu > li.has-children:hover > .sub-menu, +.cn1-header #menu > li.has-children:focus-within > .sub-menu { + display: block; +} + +.cn1-header .cn1-nav-toggle { + display: none; +} + +.cn1-header .cn1-nav-toggle-btn { + display: none; +} + +.cn1-header .cn1-nav-links { + margin-inline-start: 0; +} + +.cn1-header .cn1-dashboard-link { + border: 2px solid var(--cn1-home-dashboard-border); + border-radius: 12px; + padding: 0 28px; + line-height: 46px; + margin-top: 18px; + color: var(--cn1-home-nav-text); + font-size: 18px; + font-weight: 700; + text-decoration: none; + margin-inline-start: 24px; + transition: line-height 180ms ease, font-size 180ms ease, margin-top 180ms ease, padding 180ms ease; +} + +.cn1-theme-controls { + display: inline-flex; + align-items: center; + gap: 0; + margin-inline-start: 14px; +} + +.cn1-theme-toggle-btn { + appearance: none; + border: 0; + background: transparent; + color: var(--cn1-home-nav-text); + border-radius: 0; + padding: 4px 6px; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 20px; + cursor: pointer; + line-height: 1; +} + +.cn1-theme-toggle-btn:hover { + color: #8fb1ff; +} + +.cn1-header.cn1-header--compact .nav { + min-height: 66px; + line-height: 66px; +} + +.cn1-header.cn1-header--compact .logo a img, +.cn1-header.cn1-header--compact .logo a svg { + height: 28px; +} + +.cn1-header.cn1-header--compact #menu > li > a, +.cn1-header.cn1-header--compact #menu > li > .cn1-menu-trigger { + line-height: 66px; +} + +.cn1-header.cn1-header--compact .cn1-dashboard-link { + margin-top: 10px; + line-height: 40px; + font-size: 16px; + padding: 0 22px; +} + +.cn1-hero, +.cn1-band, +.cn1-cards, +.cn1-why, +.cn1-home-v1-link { + max-width: 1320px; + margin: 0 auto; + padding-left: 48px; + padding-right: 48px; +} + +.cn1-hero { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 44px; + align-items: center; + padding-top: 64px; + padding-bottom: 64px; +} + +.cn1-hero__eyebrow { + color: #cfdcff; + font-size: 15px; + font-weight: 700; + letter-spacing: 0.01em; +} + +.cn1-hero__title { + margin-top: 20px; + font-family: "Poppins", sans-serif; + font-feature-settings: normal; + font-kerning: auto; + font-language-override: normal; + font-optical-sizing: auto; + font-size: 40px; + font-size-adjust: none; + font-stretch: 100%; + font-style: normal; + font-weight: 700; + line-height: 1.07; + color: #f5f8ff; + max-width: 640px; +} + +.cn1-hero__platforms { + margin-top: 30px; + display: flex; + gap: 12px; + flex-wrap: wrap; +} + +.cn1-hero__platforms i { + color: #b6c7ff; + font-size: 34px; + line-height: 1; +} + +.cn1-hero__copy { + margin-top: 30px; + color: #fff; + font-family: "Poppins", sans-serif; + font-size: 17px; + font-weight: 500; + line-height: 1.3em; + max-width: 640px; +} + +.cn1-hero__trust { + margin-top: 26px; + font-size: 20px; + color: #d0dcff; + font-weight: 600; +} + +.cn1-hero__actions { + margin-top: 36px; + display: flex; + gap: 18px; + align-items: center; + flex-wrap: wrap; +} + +.cn1-btn { + display: inline-block; + font-size: 17px; + font-weight: 700; + padding: 12px 34px; + border-radius: 8px; +} + +.cn1-btn--primary { + border: 2px solid #d8e5ff; + color: #fff; +} + +.cn1-btn--ghost { + background: #fff; + color: #1a1f2f; + border-radius: 10px; + font-size: 20px; + padding: 8px 16px; +} + +.cn1-hero__art img { + width: 100%; + max-width: 680px; + margin-left: auto; +} + +.cn1-band { + text-align: center; + padding-top: 34px; + padding-bottom: 30px; +} + +.cn1-band h2 { + color: #a8beff; + font-family: "Poppins", sans-serif; + font-feature-settings: normal; + font-kerning: auto; + font-language-override: normal; + font-optical-sizing: auto; + font-size: 35px; + font-size-adjust: none; + font-stretch: 100%; + font-style: normal; + font-variant-alternates: normal; + font-variant-caps: normal; + font-variant-east-asian: normal; + font-variant-emoji: normal; + font-variant-ligatures: normal; + font-variant-numeric: normal; + font-variant-position: normal; + font-variation-settings: normal; + font-weight: 500; + line-height: 1.2; +} + +.cn1-band h2 span { + margin-left: 20px; +} + +.cn1-band__icons { + display: inline-flex; + gap: 14px; + margin-left: 18px; + vertical-align: middle; +} + +.cn1-band__icons i { + font-size: 36px; + color: #a8beff; +} + +.cn1-cards { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 30px; + padding-top: 26px; + padding-bottom: 48px; +} + +.cn1-card { + background: #374261; + border: 2px solid #1f6dff; + border-radius: 12px; + padding: 30px 28px; + min-height: 300px; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; +} + +.cn1-card::before { + font-family: "Font Awesome 5 Free"; + font-weight: 900; + content: "\f1e0"; + font-size: 52px; + line-height: 1; + color: #a8beff; + margin-bottom: 14px; +} + +.cn1-card:nth-child(2)::before { + content: "\f7d9"; +} + +.cn1-card:nth-child(3)::before { + content: "\f1fc"; +} + +.cn1-card h3 { + color: #edf2ff; + font-family: "Poppins", sans-serif; + font-feature-settings: normal; + font-kerning: auto; + font-language-override: normal; + font-optical-sizing: auto; + font-size: 20px; + font-size-adjust: none; + font-stretch: 100%; + font-style: normal; + font-variant-alternates: normal; + font-variant-caps: normal; + font-variant-east-asian: normal; + font-variant-emoji: normal; + font-variant-ligatures: normal; + font-variant-numeric: normal; + font-variant-position: normal; + font-variation-settings: normal; + font-weight: 500; + line-height: 1.2; + margin-bottom: 14px; +} + +.cn1-card p { + color: #dbe4ff; + font-family: "Poppins", sans-serif; + font-feature-settings: normal; + font-kerning: auto; + font-language-override: normal; + font-optical-sizing: auto; + font-size: 14px; + font-size-adjust: none; + font-stretch: 100%; + font-style: normal; + font-variant-alternates: normal; + font-variant-caps: normal; + font-variant-east-asian: normal; + font-variant-emoji: normal; + font-variant-ligatures: normal; + font-variant-numeric: normal; + font-variant-position: normal; + font-variation-settings: normal; + font-weight: 300; + line-height: 1.35; +} + +.cn1-card a { + color: #f5f8ff; + text-decoration: underline; + font-family: "Poppins", sans-serif; + font-feature-settings: normal; + font-kerning: auto; + font-language-override: normal; + font-optical-sizing: auto; + font-size: 12px; + font-size-adjust: none; + font-stretch: 100%; + font-style: normal; + font-variant-alternates: normal; + font-variant-caps: normal; + font-variant-east-asian: normal; + font-variant-emoji: normal; + font-variant-ligatures: normal; + font-variant-numeric: normal; + font-variant-position: normal; + font-variation-settings: normal; + font-weight: 500; + line-height: 12px; + white-space: nowrap; + overflow-wrap: break-word; + text-wrap-mode: nowrap; +} + +.cn1-card__links { + display: flex; + gap: 18px; + flex-wrap: wrap; + margin-top: auto; + justify-content: center; +} + +.cn1-card > a { + margin-top: auto; +} + +.cn1-card__links a { + margin-top: 0; +} + +.cn1-why { + padding-top: 26px; + padding-bottom: 86px; +} + +.cn1-why h2 { + text-align: center; + color: #a8beff; + font-family: "Poppins", sans-serif; + font-feature-settings: normal; + font-kerning: auto; + font-language-override: normal; + font-optical-sizing: auto; + font-size: 35px; + font-size-adjust: none; + font-stretch: 100%; + font-style: normal; + font-variation-settings: normal; + font-weight: 500; +} + +.cn1-why__grid { + margin-top: 36px; + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 28px 36px; +} + +.cn1-why__grid article h3 { + color: #e9efff; + font-family: "Poppins", sans-serif; + font-feature-settings: normal; + font-kerning: auto; + font-language-override: normal; + font-optical-sizing: auto; + font-size: 20px; + font-size-adjust: none; + font-stretch: 100%; + font-style: normal; + font-variation-settings: normal; + font-weight: 500; + margin-bottom: 10px; +} + +.cn1-why__grid article p { + color: #dbe4ff; + font-family: "Poppins", sans-serif; + font-feature-settings: normal; + font-kerning: auto; + font-language-override: normal; + font-optical-sizing: auto; + font-size: 14px; + font-size-adjust: none; + font-stretch: 100%; + font-style: normal; + font-variation-settings: normal; + font-weight: 300; + line-height: 1.35; +} + +.cn1-why__grid article i { + display: inline-block; + color: #a8beff; + font-size: 44px; + line-height: 1; + margin-bottom: 18px; +} + +.cn1-why__cta { + margin-top: 34px; + text-align: center; +} + +.cn1-why__cta a { + color: #f5f8ff; + text-decoration: underline; + font-family: "Poppins", sans-serif; + font-size: 12px; + font-weight: 500; + line-height: 12px; + white-space: nowrap; +} + +.cn1-home-v1-link { + padding-top: 0; + padding-bottom: 40px; + text-align: center; +} + +.cn1-home-v1-link a { + color: #a7c0ff; + text-decoration: underline; + font-size: 22px; +} + +.footer, +.cn1-site-footer { + background: var(--cn1-home-footer-bg); + color: var(--cn1-home-footer-text); + border-top: 1px solid rgba(255, 255, 255, 0.08); +} + +.cn1-site-footer { + max-width: none; + margin: 0; + padding: 0; + text-align: left; + line-height: 1.4; +} + +.cn1-how, +.cn1-made, +.cn1-loved, +.cn1-blog, +.cn1-cta-row, +.cn1-newsletter { + max-width: 1320px; + margin: 0 auto; + padding-left: 48px; + padding-right: 48px; +} + +.cn1-how, +.cn1-made, +.cn1-loved, +.cn1-blog, +.cn1-newsletter { + padding-top: 64px; +} + +.cn1-how h2, +.cn1-made h2, +.cn1-loved h2, +.cn1-blog h2, +.cn1-newsletter h2 { + text-align: center; + color: #a8beff; + font-family: "Poppins", sans-serif; + font-size: 35px; + font-weight: 500; +} + +.cn1-how__intro { + max-width: 780px; + margin: 18px auto 0; + color: #dbe4ff; + text-align: center; + font-size: 14px; + font-weight: 300; +} + +.cn1-how__layout { + margin-top: 42px; + display: grid; + grid-template-columns: 1fr 1.8fr 1fr; + gap: 20px; + align-items: start; +} + +.cn1-how__list h3 { + text-align: center; + color: #a8beff; + font-size: 20px; + margin-bottom: 16px; +} + +.cn1-accordion { + display: grid; + gap: 10px; +} + +.cn1-acc-item { + background: #374261; + border: 1px solid #465270; + overflow: hidden; +} + +.cn1-acc-trigger { + width: 100%; + border: 0; + background: transparent; + color: #f5f8ff; + display: grid; + grid-template-columns: auto 1fr auto; + align-items: center; + gap: 12px; + text-align: left; + padding: 14px 16px; + font-size: 20px; + font-weight: 500; + cursor: pointer; +} + +.cn1-acc-icon { + width: 20px; + text-align: center; +} + +.cn1-acc-icon--ok { + color: #96dc53; +} + +.cn1-acc-icon--no { + color: #ff486e; +} + +.cn1-acc-icon--q { + color: #5e86ff; +} + +.cn1-acc-panel { + max-height: 0; + overflow: hidden; + transition: max-height 260ms ease; + background: #c8cedd; +} + +.cn1-acc-panel p { + margin: 0; + padding: 16px 24px; + color: #0d1847; + font-size: 14px; + font-weight: 400; + line-height: 1.35; +} + +.cn1-acc-caret { + color: #f5f8ff; + text-align: right; +} + +.cn1-how__diagram img { + width: 100%; + border-radius: 8px; +} + +.cn1-carousel { + margin-top: 34px; + position: relative; +} + +.cn1-carousel__viewport { + overflow: hidden; +} + +.cn1-carousel__track { + display: flex; + transition: transform 320ms ease; +} + +.cn1-carousel__slide { + min-width: 100%; + box-sizing: border-box; +} + +.cn1-carousel__prev, +.cn1-carousel__next { + position: absolute; + top: 50%; + transform: translateY(-50%); + border: 0; + background: none; + color: #a8beff; + font-size: 42px; + cursor: pointer; +} + +.cn1-carousel__prev { + left: -40px; +} + +.cn1-carousel__next { + right: -40px; +} + +.cn1-carousel__dots { + margin-top: 16px; + display: flex; + justify-content: center; + gap: 10px; +} + +.cn1-carousel__dots button { + width: 10px; + height: 10px; + border-radius: 50%; + border: 0; + background: rgba(168, 190, 255, 0.35); + cursor: pointer; +} + +.cn1-carousel__dots button.is-active { + background: #a8beff; +} + +.cn1-made .cn1-carousel__slide { + text-align: center; + max-width: 760px; + margin: 0 auto; +} + +.cn1-made .cn1-carousel__slide img { + width: 370px; + max-width: 100%; + display: block; + margin: 0 auto; +} + +.cn1-made .cn1-carousel__slide h3 { + margin-top: 14px; + color: #dbe4ff; + font-size: 20px; + font-weight: 500; +} + +.cn1-made .cn1-carousel__slide p { + color: #dbe4ff; + font-size: 14px; + font-weight: 300; +} + +.cn1-made .cn1-carousel__slide a { + color: #a8beff; + font-size: 22px; +} + +.cn1-made .cn1-carousel { + max-width: 920px; + margin: 34px auto 0; +} + +.cn1-made .cn1-carousel__prev { + left: -12px; +} + +.cn1-made .cn1-carousel__next { + right: -12px; +} + +.cn1-loved__grid { + margin-top: 32px; + display: grid; + grid-template-columns: 1.1fr 0.9fr; + gap: 26px; + align-items: center; +} + +.cn1-loved__grid > img { + width: 100%; + opacity: 0.95; + filter: brightness(1.12) contrast(1.1); +} + +.cn1-loved__grid .cn1-carousel { + margin-top: 0; +} + +.cn1-loved__grid .cn1-carousel__prev, +.cn1-loved__grid .cn1-carousel__next { + display: none; +} + +.cn1-loved__grid .cn1-carousel__slide { + text-align: center; +} + +.cn1-loved__grid .cn1-carousel__slide blockquote { + position: relative; + border: 2px solid #1f6dff; + border-radius: 8px; + margin: 0 auto; + padding: 24px 28px; + color: #f5f8ff; + font-size: 20px; + line-height: 1.35; + font-weight: 600; + max-width: 560px; +} + +.cn1-loved__grid .cn1-carousel__slide blockquote span { + display: block; +} + +.cn1-loved__grid .cn1-carousel__slide blockquote span + span { + margin-top: 12px; + color: #a8beff; + font-style: italic; + font-weight: 500; +} + +.cn1-loved__grid .cn1-carousel__slide blockquote::after { + content: ""; + position: absolute; + left: 50%; + bottom: -9px; + width: 16px; + height: 16px; + background: #1b1e27; + border-right: 2px solid #1f6dff; + border-bottom: 2px solid #1f6dff; + transform: translateX(-50%) rotate(45deg); +} + +.cn1-loved__grid .cn1-carousel__slide p { + color: #a8beff; + font-size: 14px; + font-weight: 300; +} + +.cn1-loved__grid .cn1-carousel__slide img { + width: 54px; + height: 54px; + border-radius: 50%; + margin: 20px auto 0; +} + +.cn1-loved__grid .cn1-carousel__slide h3 { + color: #f5f8ff; + font-size: 20px; + font-weight: 500; + margin: 12px 0 6px; +} + +.cn1-loved__grid .cn1-carousel__slide h3 + p { + max-width: 620px; + margin: 0 auto; + font-weight: 500; +} + +.cn1-blog__grid { + margin-top: 0; + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 24px; +} + +.cn1-blog .cn1-carousel__prev, +.cn1-blog .cn1-carousel__next { + display: none; +} + +.cn1-blog__grid article { + background: #374261; + border: 1px solid #465270; + border-radius: 6px; + overflow: hidden; +} + +.cn1-blog__grid article img { + width: 100%; + display: block; + aspect-ratio: 16 / 10; + object-fit: cover; +} + +.cn1-blog__grid article > div { + padding: 14px 16px; +} + +.cn1-blog__grid h3, +.cn1-blog__grid h3 a { + color: #f5f8ff; + font-size: 20px; + font-weight: 500; + text-decoration: none; + text-align: center; +} + +.cn1-blog__grid p { + margin: 10px 0 0; + color: #8d98b8; + font-size: 12px; + text-align: center; +} + +.cn1-cta-row { + margin-top: 56px; + border: 1px solid #1f6dff; + border-radius: 10px; + display: grid; + grid-template-columns: 1fr 1fr; + overflow: hidden; + padding-left: 0; + padding-right: 0; + background: #374261; +} + +.cn1-cta-row article { + background: #374261; + padding: 34px 40px; + display: grid; + grid-template-columns: auto 1fr auto; + align-items: center; + gap: 24px; +} + +.cn1-cta-row article + article { + border-left: 1px solid #1f6dff; +} + +.cn1-cta-row article i { + color: #a8beff; + font-size: 54px; +} + +.cn1-cta-row article h3 { + color: #f5f8ff; + font-size: 20px; + font-weight: 500; + margin: 0; +} + +.cn1-cta-row article a { + border: 2px solid #d8e5ff; + color: #f5f8ff; + padding: 10px 26px; + font-size: 20px; + font-weight: 500; + text-decoration: none; +} + +.cn1-newsletter p { + text-align: center; + color: #dbe4ff; + font-size: 14px; +} + +.cn1-newsletter form { + margin: 24px auto 0; + max-width: 1060px; + display: grid; + grid-template-columns: 1fr 1fr auto; + gap: 16px; +} + +.cn1-newsletter input { + background: #c8cedd; + border: 0; + border-radius: 6px; + padding: 12px 16px; + font-size: 20px; +} + +.cn1-newsletter button { + border: 2px solid #d8e5ff; + background: transparent; + color: #f5f8ff; + border-radius: 6px; + padding: 12px 28px; + font-size: 20px; +} + +.cn1-bottom-links { + max-width: 1320px; + margin: 60px auto 0; + padding: 46px 48px 60px; + display: grid; + grid-template-columns: 1.1fr 1fr 0.6fr; + gap: 30px; + border-top: 1px solid rgba(255, 255, 255, 0.15); +} + +.cn1-bottom-links__col h3 { + color: #afc1ff; + font-family: "Roboto", sans-serif; + font-size: 20px; + font-weight: 500; + line-height: 26px; +} + +.cn1-bottom-links__col ul { + columns: 2; + list-style: none; + padding: 0; + margin: 22px 0 0; +} + +.cn1-bottom-links__col li { + margin: 0 0 12px; + break-inside: avoid; + position: relative; + padding-left: 18px; +} + +.cn1-bottom-links__col li::before { + content: "\203A"; + position: absolute; + left: 0; + top: 0; + color: #818698; + font-size: 20px; + line-height: 16px; +} + +.cn1-bottom-links__col a { + color: #818698; + text-decoration: none; + font-family: "Poppins", sans-serif; + font-size: 16px; + font-weight: 400; + line-height: 16px; + padding-left: 5px; + transition: color 0.3s ease; +} + +.cn1-bottom-links__col a:hover { + color: #a2aed0; +} + +.cn1-bottom-links__brand { + text-align: center; + align-self: center; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.cn1-bottom-links__brand .cn1-footer-logo { + width: 205px; + max-width: 100%; +} + +.cn1-footer-logo--light { + display: none; +} + +body:not(.dark) .cn1-footer-logo--dark { + display: none; +} + +body:not(.dark) .cn1-footer-logo--light { + display: block; +} + +.cn1-bottom-links__brand p { + color: #a8beff; + font-family: "Poppins", sans-serif; + font-size: 17px; + font-weight: 500; + line-height: 1.2; + margin: 16px 0 0; +} + +.cn1-bottom-links__stats { + text-align: right; + color: #afc1ff; + font-size: 13px; + align-self: center; +} + +.cn1-bottom-links__stats p { + margin: 0 0 34px; +} + +.cn1-bottom-links__stats span { + color: #afc1ff; + font-family: "Poppins", sans-serif; + font-size: 13px; + font-weight: 500; + line-height: 13px; +} + +.cn1-bottom-links__stats strong { + color: #eaeffd; + font-family: "Helvetica Neue", sans-serif; + font-size: 20px; + font-weight: 500; + line-height: 22px; + display: block; +} + +.cn1-footer-meta { + max-width: 1320px; + margin: 0 auto; + padding: 0 48px 28px; + color: #818698; + display: flex; + justify-content: space-between; + gap: 24px; + border-top: 1px solid rgba(255, 255, 255, 0.1); +} + +.cn1-footer-meta p { + margin: 18px 0 0; + font-family: "Poppins", sans-serif; + font-size: 16px; + line-height: 1.35; +} + +.cn1-footer-meta a { + color: #7ca9ff; + text-decoration: none; +} + +.cn1-footer-meta a:hover { + color: #9fbeff; +} + +body:not(.dark).cn1-homepage .cn1-hero__title, +body:not(.dark).cn1-homepage .cn1-hero__copy, +body:not(.dark).cn1-homepage .cn1-hero__trust, +body:not(.dark).cn1-homepage .cn1-band h2, +body:not(.dark).cn1-homepage .cn1-why h2, +body:not(.dark).cn1-homepage .cn1-how h2, +body:not(.dark).cn1-homepage .cn1-made h2, +body:not(.dark).cn1-homepage .cn1-loved h2, +body:not(.dark).cn1-homepage .cn1-blog h2, +body:not(.dark).cn1-homepage .cn1-newsletter h2 { + color: #1e3fba; +} + +body:not(.dark).cn1-homepage .cn1-hero__eyebrow { + color: #516084; +} + +body:not(.dark).cn1-homepage .cn1-cards .cn1-card, +body:not(.dark).cn1-homepage .cn1-cta-row article, +body:not(.dark).cn1-homepage .cn1-blog__grid article { + background: var(--cn1-home-card-bg); + border-color: var(--cn1-home-card-border); +} + +body:not(.dark).cn1-homepage .cn1-card h3, +body:not(.dark).cn1-homepage .cn1-card p, +body:not(.dark).cn1-homepage .cn1-card a, +body:not(.dark).cn1-homepage .cn1-why__grid article h3, +body:not(.dark).cn1-homepage .cn1-why__grid article p, +body:not(.dark).cn1-homepage .cn1-how__intro, +body:not(.dark).cn1-homepage .cn1-how__list h3, +body:not(.dark).cn1-homepage .cn1-made .cn1-carousel__slide h3, +body:not(.dark).cn1-homepage .cn1-made .cn1-carousel__slide p, +body:not(.dark).cn1-homepage .cn1-loved__grid .cn1-carousel__slide h3, +body:not(.dark).cn1-homepage .cn1-loved__grid .cn1-carousel__slide p, +body:not(.dark).cn1-homepage .cn1-blog__grid h3, +body:not(.dark).cn1-homepage .cn1-blog__grid h3 a, +body:not(.dark).cn1-homepage .cn1-cta-row article h3 { + color: var(--cn1-home-card-text); +} + +body:not(.dark).cn1-homepage .cn1-btn--primary, +body:not(.dark).cn1-homepage .cn1-dashboard-link { + color: #173287; +} + +body:not(.dark).cn1-homepage .cn1-bottom-links__col a, +body:not(.dark).cn1-homepage .cn1-footer-meta p { + color: #65739a; +} + +body:not(.dark).cn1-homepage .cn1-loved__grid .cn1-carousel__slide blockquote { + color: #1b274e; + background: #e7ecfb; + border-color: #2b66ea; +} + +body:not(.dark).cn1-homepage .cn1-loved__grid .cn1-carousel__slide blockquote span + span { + color: #4a5f97; +} + +body:not(.dark).cn1-homepage .cn1-loved__grid .cn1-carousel__slide blockquote::after { + background: #e7ecfb; + border-right-color: #2b66ea; + border-bottom-color: #2b66ea; +} + +body:not(.dark).cn1-homepage .cn1-cta-row article a { + color: #173287; + border-color: #173287; +} + +body:not(.dark).cn1-homepage .cn1-bottom-links__stats strong { + color: #1b274e; +} + +body:not(.dark).cn1-homepage .cn1-bottom-links__stats span { + color: #4f648f; +} + +body:not(.dark) .cn1-theme-toggle-btn { + color: #173287; +} + +@media (max-width: 1400px) { + .cn1-homepage .header::before { + font-size: 18px; + } + + .cn1-header::before { + font-size: 18px; + } + + .cn1-homepage .logo a { + font-size: 0; + } + + .cn1-homepage .logo a img, + .cn1-homepage .logo a svg { + height: 30px; + } + + .cn1-header .logo a img, + .cn1-header .logo a svg { + height: 30px; + } + + .cn1-brand-logo { + height: 30px; + } + + .cn1-homepage #menu a { + font-size: 16px; + } + + .cn1-homepage #menu > li > a, + .cn1-homepage #menu > li > details > summary { + font-size: 16px; + } + + .cn1-header #menu > li > a, + .cn1-header #menu > li > .cn1-menu-trigger { + font-size: 16px; + } + + .cn1-header #menu > li > .cn1-menu-trigger { + font-size: 16px; + } + + .cn1-homepage .cn1-dashboard-link { + margin-top: 20px; + line-height: 44px; + font-size: 16px; + } + + .cn1-header .cn1-dashboard-link { + margin-top: 20px; + line-height: 44px; + font-size: 16px; + } + + .cn1-hero__eyebrow { + font-size: 14px; + } + + .cn1-hero__title { + font-size: 40px; + } + + .cn1-hero__copy { + font-size: 17px; + } + + .cn1-hero__trust { + font-size: 18px; + } + + .cn1-btn { + font-size: 16px; + } + + .cn1-btn--ghost { + font-size: 18px; + } + + .cn1-band h2, + .cn1-why h2 { + font-size: 35px; + } + + .cn1-card h3, + .cn1-why__grid article h3 { + font-size: 20px; + } + + .cn1-card p, + .cn1-why__grid article p { + font-size: 14px; + } + + .cn1-card a, + .cn1-why__cta a { + font-size: 18px; + } + + .cn1-how h2, + .cn1-made h2, + .cn1-loved h2, + .cn1-blog h2, + .cn1-newsletter h2 { + font-size: 30px; + } +} + +@media (max-width: 980px) { + .cn1-homepage .header { + position: static; + padding-top: 34px; + } + + .cn1-header { + position: static; + padding-top: 34px; + } + + .cn1-homepage .nav { + flex-wrap: wrap; + min-height: 64px; + line-height: 1.2; + padding: 16px 0; + } + + .cn1-header .nav { + flex-wrap: wrap; + min-height: 64px; + line-height: 1.2; + padding: 16px 0; + } + + .cn1-homepage .logo a { + font-size: 0; + padding-left: 0; + } + + .cn1-homepage .logo a::before { + content: none; + } + + .cn1-homepage .logo a img, + .cn1-homepage .logo a svg { + height: 26px; + } + + .cn1-header .logo a img, + .cn1-header .logo a svg { + height: 26px; + } + + .cn1-brand-logo { + height: 26px; + } + + .cn1-homepage .logo, + .cn1-homepage #menu { + margin: 0 16px; + } + + .cn1-homepage .cn1-nav-toggle-btn { + margin-left: auto; + margin-right: 14px; + width: 42px; + height: 42px; + border: 2px solid #d9e3ff; + border-radius: 10px; + display: inline-flex; + align-items: center; + justify-content: center; + color: #fff; + font-size: 21px; + line-height: 1; + cursor: pointer; + } + + .cn1-header .cn1-nav-toggle-btn { + margin-left: auto; + margin-right: 14px; + width: 42px; + height: 42px; + border: 2px solid #d9e3ff; + border-radius: 10px; + display: inline-flex; + align-items: center; + justify-content: center; + color: #fff; + font-size: 21px; + line-height: 1; + cursor: pointer; + } + + .cn1-homepage .cn1-nav-toggle-btn .fa-times { + display: none; + } + + .cn1-header .cn1-nav-toggle-btn .fa-times { + display: none; + } + + .cn1-homepage .cn1-dashboard-link { + margin: 0 16px 0 0; + line-height: 36px; + padding: 0 16px; + font-size: 14px; + } + + .cn1-header .cn1-dashboard-link { + margin: 0 16px 0 0; + line-height: 36px; + padding: 0 16px; + font-size: 14px; + } + + .cn1-homepage .cn1-nav-links { + display: none; + width: 100%; + margin: 14px 0 0 0; + background: #c8cedd; + border-radius: 0 0 12px 12px; + overflow: hidden; + } + + .cn1-header .cn1-nav-links { + display: none; + width: 100%; + margin: 14px 0 0 0; + background: #c8cedd; + border-radius: 0 0 12px 12px; + overflow: hidden; + } + + .cn1-homepage .cn1-nav-toggle:checked + .cn1-nav-toggle-btn .fa-bars { + display: none; + } + + .cn1-header .cn1-nav-toggle:checked + .cn1-nav-toggle-btn .fa-bars { + display: none; + } + + .cn1-homepage .cn1-nav-toggle:checked + .cn1-nav-toggle-btn .fa-times { + display: inline-block; + } + + .cn1-header .cn1-nav-toggle:checked + .cn1-nav-toggle-btn .fa-times { + display: inline-block; + } + + .cn1-homepage .cn1-nav-toggle:checked ~ .cn1-nav-links { + display: block; + } + + .cn1-header .cn1-nav-toggle:checked ~ .cn1-nav-links { + display: block; + } + + .cn1-homepage #menu { + display: block; + margin: 0; + width: 100%; + } + + .cn1-header #menu { + display: block; + margin: 0; + width: 100%; + } + + .cn1-homepage #menu li + li { + margin-inline-start: 0; + border-top: 1px solid #b1b9cc; + } + + .cn1-header #menu li + li { + margin-inline-start: 0; + border-top: 1px solid #b1b9cc; + } + + .cn1-homepage #menu a { + color: #0d1847; + font-size: 16px; + padding: 16px 22px; + line-height: 1.25; + } + + .cn1-homepage #menu > li > a, + .cn1-homepage #menu > li > details > summary { + color: #0d1847; + line-height: 1.25; + display: block; + padding: 16px 22px; + font-size: 16px; + } + + .cn1-header #menu > li > a, + .cn1-header #menu > li > .cn1-menu-trigger { + color: #0d1847; + line-height: 1.25; + display: block; + padding: 16px 22px; + font-size: 16px; + text-align: left; + width: 100%; + } + + .cn1-homepage #menu > li > details > summary::after, + .cn1-header #menu > li > .cn1-menu-trigger::after { + float: right; + } + + .cn1-homepage #menu .sub-menu { + position: static; + min-width: 0; + border-radius: 0; + box-shadow: none; + background: #d8ddea; + } + + .cn1-header #menu .sub-menu { + display: none; + position: static; + min-width: 0; + border-radius: 0; + box-shadow: none; + background: #d8ddea; + } + + .cn1-homepage #menu .sub-menu a { + padding: 15px 28px; + font-size: 15px; + } + + .cn1-header #menu .sub-menu a { + padding: 15px 28px; + font-size: 15px; + } + + .cn1-header #menu > li.has-children.open > .sub-menu { + display: block !important; + } + + .cn1-theme-controls { + width: 100%; + justify-content: center; + padding: 10px 12px 4px; + border-top: 1px solid #b1b9cc; + margin-inline-start: 0; + background: #d8ddea; + } + + .cn1-theme-toggle-btn { + color: #173287; + font-size: 22px; + } + + .cn1-hero, + .cn1-band, + .cn1-cards, + .cn1-why, + .cn1-home-v1-link, + .cn1-how, + .cn1-made, + .cn1-loved, + .cn1-blog, + .cn1-cta-row, + .cn1-newsletter { + padding-left: 18px; + padding-right: 18px; + } + + .cn1-hero { + grid-template-columns: 1fr; + padding-top: 32px; + } + + .cn1-hero__title { + font-size: 44px; + } + + .cn1-hero__platforms i { + font-size: 28px; + } + + .cn1-hero__copy { + font-size: 18px; + } + + .cn1-hero__trust { + font-size: 18px; + } + + .cn1-btn { + font-size: 16px; + } + + .cn1-band h2 { + font-size: 36px; + line-height: 1.2; + } + + .cn1-band h2 span { + margin-left: 0; + } + + .cn1-band__icons { + display: none; + } + + .cn1-cards, + .cn1-why__grid { + grid-template-columns: 1fr; + } + + .cn1-card { + min-height: 0; + } + + .cn1-why h2 { + font-size: 40px; + } + + .cn1-how__layout, + .cn1-loved__grid, + .cn1-blog__grid, + .cn1-cta-row, + .cn1-newsletter form { + grid-template-columns: 1fr; + } + + .cn1-cta-row article + article { + border-left: 0; + border-top: 1px solid #1f6dff; + } + + .cn1-bottom-links__col ul { + columns: 1; + } + + .cn1-bottom-links__stats, + .cn1-bottom-links__brand { + text-align: left; + } + + .cn1-bottom-links__brand .cn1-footer-logo { + display: none; + } + + .cn1-bottom-links { + padding: 34px 18px 40px; + } + + .cn1-footer-meta { + padding: 0 18px 20px; + flex-direction: column; + } +} diff --git a/docs/website/assets/css/extended/cn1-howdoi.css b/docs/website/assets/css/extended/cn1-howdoi.css new file mode 100644 index 0000000000..64d3ef6518 --- /dev/null +++ b/docs/website/assets/css/extended/cn1-howdoi.css @@ -0,0 +1,256 @@ +.cn1-howdoi-index { + --cn1-howdoi-bg: #eef2fb; + --cn1-howdoi-card: #ffffff; + --cn1-howdoi-border: #d6e0f6; + --cn1-howdoi-title: #102154; + --cn1-howdoi-text: #4b5f8f; + --cn1-howdoi-accent: #1d52ff; + --cn1-howdoi-chip: #edf2ff; + --cn1-howdoi-shadow: 0 18px 32px -24px rgba(16, 33, 84, 0.35); + background: var(--cn1-howdoi-bg); + margin: 0 calc(50% - 50vw); + padding: 2.5rem 0 4rem; +} + +body.dark .cn1-howdoi-index { + --cn1-howdoi-bg: #06103a; + --cn1-howdoi-card: #131f54; + --cn1-howdoi-border: #31438c; + --cn1-howdoi-title: #eff4ff; + --cn1-howdoi-text: #b7c9ff; + --cn1-howdoi-accent: #95b8ff; + --cn1-howdoi-chip: rgba(255, 255, 255, 0.1); + --cn1-howdoi-shadow: 0 18px 32px -24px rgba(4, 9, 28, 0.72); +} + +.cn1-howdoi-index .post-header, +.cn1-howdoi-grid { + max-width: 1240px; + margin-inline: auto; + padding-inline: 1.25rem; +} + +.cn1-howdoi-index .post-header { + margin-bottom: 1.4rem; +} + +.cn1-howdoi-index__eyebrow { + margin: 0 0 0.6rem; + letter-spacing: 0.08em; + text-transform: uppercase; + font-size: 0.78rem; + font-weight: 700; + color: var(--cn1-howdoi-accent); +} + +.cn1-howdoi-index .post-title { + margin: 0; + color: var(--cn1-howdoi-title); +} + +.cn1-howdoi-index .post-description, +.cn1-howdoi-index .content { + color: var(--cn1-howdoi-text); +} + +.cn1-howdoi-index__count { + margin: 0.8rem 0 0; + font-weight: 600; + color: var(--cn1-howdoi-accent); +} + +.cn1-howdoi-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + gap: 1rem; +} + +.cn1-howdoi-card { + border: 1px solid var(--cn1-howdoi-border); + background: var(--cn1-howdoi-card); + border-radius: 16px; + overflow: hidden; + box-shadow: var(--cn1-howdoi-shadow); +} + +.cn1-howdoi-card__thumb { + position: relative; + display: block; + aspect-ratio: 16 / 9; + overflow: hidden; +} + +.cn1-howdoi-card__thumb img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + transition: transform 0.25s ease; +} + +.cn1-howdoi-card:hover .cn1-howdoi-card__thumb img { + transform: scale(1.03); +} + +.cn1-howdoi-card__play { + position: absolute; + right: 0.85rem; + bottom: 0.85rem; + width: 2rem; + height: 2rem; + border-radius: 999px; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.8rem; + background: rgba(15, 29, 76, 0.82); + color: #fff; +} + +.cn1-howdoi-card__body { + padding: 0.95rem 1rem 1rem; +} + +.cn1-howdoi-card__body h2 { + margin: 0; + font-size: 1.03rem; + line-height: 1.3; +} + +.cn1-howdoi-card__body h2 a { + color: var(--cn1-howdoi-title); +} + +.cn1-howdoi-card__body p { + margin: 0.5rem 0 0; + color: var(--cn1-howdoi-text); + font-size: 0.95rem; + line-height: 1.45; +} + +.cn1-howdoi-card__meta { + margin-top: 0.8rem; + display: flex; + gap: 0.45rem; + flex-wrap: wrap; +} + +.cn1-howdoi-card__meta span { + font-size: 0.72rem; + text-transform: uppercase; + letter-spacing: 0.05em; + padding: 0.25rem 0.5rem; + border-radius: 999px; + background: var(--cn1-howdoi-chip); + color: var(--cn1-howdoi-title); +} + +.cn1-howdoi-single { + --cn1-howdoi-panel: rgba(29, 82, 255, 0.08); + --cn1-howdoi-panel-border: rgba(29, 82, 255, 0.25); +} + +body.dark .cn1-howdoi-single { + --cn1-howdoi-panel: rgba(175, 193, 255, 0.1); + --cn1-howdoi-panel-border: rgba(175, 193, 255, 0.25); +} + +.cn1-howdoi-single .post-header { + margin-bottom: 1rem; +} + +.cn1-howdoi-single__eyebrow { + margin: 0.1rem 0 0.5rem; + font-size: 0.76rem; + letter-spacing: 0.08em; + text-transform: uppercase; + font-weight: 700; + color: var(--cn1-howdoi-accent, #1d52ff); +} + +.cn1-howdoi-single__layout { + display: grid; + grid-template-columns: 300px 1fr; + gap: 1.1rem; + align-items: start; +} + +.cn1-howdoi-single__aside { + position: sticky; + top: 6.5rem; + border: 1px solid var(--cn1-howdoi-panel-border); + background: var(--cn1-howdoi-panel); + border-radius: 14px; + padding: 0.9rem; + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.cn1-howdoi-single__aside img { + width: 100%; + border-radius: 10px; +} + +.cn1-howdoi-single__watch, +.cn1-howdoi-single__back { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.45rem; + padding: 0.52rem 0.7rem; + border-radius: 9px; + border: 1px solid var(--cn1-howdoi-panel-border); + font-weight: 600; + text-decoration: none; +} + +.cn1-howdoi-single__watch { + background: var(--cn1-howdoi-accent, #1d52ff); + color: #fff; + border-color: transparent; +} + +.cn1-howdoi-single__watch:hover { + filter: brightness(1.05); +} + +.cn1-howdoi-single__back { + color: inherit; +} + +.cn1-howdoi-single__tags { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; +} + +.cn1-howdoi-single__tags span { + font-size: 0.74rem; + text-transform: uppercase; + letter-spacing: 0.05em; + padding: 0.22rem 0.5rem; + border-radius: 999px; + border: 1px solid var(--cn1-howdoi-panel-border); +} + +.cn1-howdoi-single__content { + border: 1px solid var(--cn1-howdoi-panel-border); + background: var(--cn1-howdoi-panel); + border-radius: 14px; + padding: 1.2rem 1.25rem; +} + +.cn1-howdoi-single__content h4 { + margin-top: 0.8rem; +} + +@media (max-width: 960px) { + .cn1-howdoi-single__layout { + grid-template-columns: 1fr; + } + + .cn1-howdoi-single__aside { + position: static; + } +} diff --git a/docs/website/assets/css/extended/cn1-introduction.css b/docs/website/assets/css/extended/cn1-introduction.css new file mode 100644 index 0000000000..79913d4798 --- /dev/null +++ b/docs/website/assets/css/extended/cn1-introduction.css @@ -0,0 +1,86 @@ +.post-single--introduction .post-content > h2 { + margin-top: 1.9rem; + margin-bottom: 0.65rem; + padding: 0.65rem 0.9rem; + border-left: 4px solid #1d52ff; + border-radius: 10px; + background: rgba(29, 82, 255, 0.08); +} + +body.dark .post-single--introduction .post-content > h2 { + border-left-color: #afc1ff; + background: rgba(175, 193, 255, 0.12); +} + +.post-single--introduction .post-content > h3 { + margin-top: 1.2rem; + margin-bottom: 0.45rem; +} + +.post-single--introduction .post-content img[src*="Group-1851.png"] { + display: block; + width: min(820px, 100%); + margin: 1rem auto 1.4rem; +} + +.post-single--introduction .post-content img[src*="Group-2326.svg"] { + width: min(420px, 100%); + float: right; + margin: 0 0 1rem 1.2rem; +} + +.post-single--introduction .post-content details { + margin: 0.7rem 0; + border: 1px solid rgba(29, 82, 255, 0.28); + border-radius: 10px; + background: rgba(29, 82, 255, 0.04); + overflow: hidden; +} + +body.dark .post-single--introduction .post-content details { + border-color: rgba(175, 193, 255, 0.3); + background: rgba(175, 193, 255, 0.08); +} + +.post-single--introduction .post-content details summary { + list-style: none; + cursor: pointer; + padding: 0.7rem 0.95rem; + font-weight: 600; + color: #1d52ff; +} + +body.dark .post-single--introduction .post-content details summary { + color: #afc1ff; +} + +.post-single--introduction .post-content details summary::-webkit-details-marker { + display: none; +} + +.post-single--introduction .post-content details[open] summary { + border-bottom: 1px solid rgba(29, 82, 255, 0.2); +} + +body.dark .post-single--introduction .post-content details[open] summary { + border-bottom-color: rgba(175, 193, 255, 0.25); +} + +.post-single--introduction .post-content details > :not(summary) { + padding: 0.8rem 0.95rem 0.9rem; + margin: 0; +} + +.post-single--introduction .post-content::after { + content: ""; + display: block; + clear: both; +} + +@media (max-width: 900px) { + .post-single--introduction .post-content img[src*="Group-2326.svg"] { + float: none; + display: block; + margin: 0.4rem auto 1rem; + } +} diff --git a/docs/website/assets/css/extended/cn1-libs.css b/docs/website/assets/css/extended/cn1-libs.css new file mode 100644 index 0000000000..5b38c96dca --- /dev/null +++ b/docs/website/assets/css/extended/cn1-libs.css @@ -0,0 +1,101 @@ +.cn1-libs-page__intro { + margin-bottom: 1.25rem; +} + +.cn1-libs-page__warning { + margin: 1rem 0 0; + padding: 0.85rem 1rem; + border: 1px solid rgba(245, 164, 72, 0.5); + border-radius: 10px; + background: rgba(245, 164, 72, 0.12); + color: #ffd8a6; +} + +body.light .cn1-libs-page__warning { + background: rgba(245, 164, 72, 0.14); + color: #5f3f10; +} + +.cn1-libs-grid { + margin-top: 1.1rem; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: 0.9rem; +} + +.cn1-libs-card { + border: 1px solid var(--cn1-course-card-border, rgba(29, 82, 255, 0.45)); + border-radius: 12px; + background: var(--cn1-course-card-bg, rgba(68, 82, 123, 0.25)); + padding: 0.95rem; + display: flex; + flex-direction: column; + gap: 0.55rem; +} + +.cn1-libs-card h2 { + margin: 0; + font-size: 1.02rem; + line-height: 1.3; + color: var(--cn1-course-link-strong, #f5f8ff); +} + +.cn1-libs-card__meta { + margin-top: 0.4rem; + display: flex; + flex-wrap: wrap; + gap: 0.35rem; +} + +.cn1-libs-card__meta span { + display: inline-block; + padding: 0.15rem 0.5rem; + border-radius: 999px; + font-size: 0.72rem; + font-weight: 600; + color: var(--cn1-course-link-strong, #f5f8ff); + border: 1px solid var(--cn1-course-card-border, rgba(29, 82, 255, 0.45)); + background: rgba(8, 17, 55, 0.22); +} + +body.light .cn1-libs-card__meta span { + background: rgba(255, 255, 255, 0.72); +} + +.cn1-libs-card p { + margin: 0; + color: var(--cn1-course-soft-text, rgba(217, 228, 255, 0.85)); + font-size: 0.92rem; + line-height: 1.45; +} + +.cn1-libs-card__cta { + margin-top: auto; + display: inline-flex; + align-self: flex-start; + text-decoration: none; + font-weight: 600; + font-size: 0.86rem; + color: var(--cn1-course-link-strong, #f5f8ff); + border: 1px solid var(--cn1-course-card-border, rgba(29, 82, 255, 0.45)); + border-radius: 8px; + padding: 0.45rem 0.65rem; + background: rgba(8, 17, 55, 0.22); +} + +body.light .cn1-libs-card__cta { + background: rgba(255, 255, 255, 0.76); +} + +.cn1-libs-card__cta:hover { + border-color: var(--cn1-course-link, #afc1ff); + color: var(--cn1-course-link, #afc1ff); +} + +.cn1-libs-empty { + margin-top: 1rem; + border: 1px dashed var(--cn1-course-card-border, rgba(29, 82, 255, 0.45)); + border-radius: 12px; + padding: 1rem; + color: var(--cn1-course-soft-text, rgba(217, 228, 255, 0.85)); +} diff --git a/docs/website/assets/css/extended/cn1-markdown.css b/docs/website/assets/css/extended/cn1-markdown.css new file mode 100644 index 0000000000..0970028298 --- /dev/null +++ b/docs/website/assets/css/extended/cn1-markdown.css @@ -0,0 +1,131 @@ +.main:has(> .post-single) { + max-width: min(1180px, calc(100vw - 32px)); + padding-inline: 24px; +} + +.post-single { + font-family: "Poppins", sans-serif; +} + +.post-single .post-title { + margin: 0; + color: rgb(28, 81, 255); + font-family: "Poppins", sans-serif; + font-size: 35px; + font-weight: 500; + line-height: 45.5px; +} + +body.dark .post-single .post-title { + color: #f5f8ff; +} + +.post-single .post-content, +.post-single .post-description, +.post-single .post-meta, +.post-single .post-content p, +.post-single .post-content li, +.post-single .post-content a, +.post-single .post-content blockquote { + font-family: "Poppins", sans-serif; +} + +.post-single .post-content { + color: #273457; +} + +body.dark .post-single .post-content { + color: #dbe4ff; +} + +.post-single .post-content h1, +.post-single .post-content h2, +.post-single .post-content h3, +.post-single .post-content h4, +.post-single .post-content h5, +.post-single .post-content h6 { + font-family: "Poppins", sans-serif; + font-weight: 500; + color: rgb(28, 81, 255); + line-height: 1.3; +} + +body.dark .post-single .post-content h1, +body.dark .post-single .post-content h2, +body.dark .post-single .post-content h3, +body.dark .post-single .post-content h4, +body.dark .post-single .post-content h5, +body.dark .post-single .post-content h6 { + color: #f5f8ff; +} + +.post-single .post-content .cn1-embed { + margin: 16px 0 24px; +} + +.post-single .post-content .cn1-embed iframe { + width: 100%; + max-width: 100%; + min-height: 360px; + border: 0; +} + +.post-single .post-content h1 { + font-size: 35px; +} + +.post-single .post-content h2 { + font-size: 30px; +} + +.post-single .post-content h3 { + font-size: 26px; +} + +.post-single .post-content h4 { + font-size: 22px; +} + +.post-single .post-content h5 { + font-size: 18px; +} + +.post-single .post-content h6 { + font-size: 16px; +} + +@media (max-width: 900px) { + .main:has(> .post-single) { + max-width: calc(100vw - 20px); + padding-inline: 14px; + } + + .post-single .post-title { + font-size: 30px; + line-height: 1.3; + } + + .post-single .post-content h1 { + font-size: 30px; + } + + .post-single .post-content h2 { + font-size: 27px; + } + + .post-single .post-content h3 { + font-size: 24px; + } + + .post-single .post-content h4 { + font-size: 21px; + } + + .post-single .post-content h5 { + font-size: 18px; + } + + .post-single .post-content h6 { + font-size: 16px; + } +} diff --git a/docs/website/assets/css/extended/cn1-press.css b/docs/website/assets/css/extended/cn1-press.css new file mode 100644 index 0000000000..31a4027fa6 --- /dev/null +++ b/docs/website/assets/css/extended/cn1-press.css @@ -0,0 +1,320 @@ +.post-single--press { + font-family: "Poppins", sans-serif; +} + +.post-single--press .post-header { + margin-bottom: 16px; +} + +.post-single--press .post-title { + margin-bottom: 8px; +} + +.post-single--press .post-description { + margin: 0; + color: #4a5678; + font-size: 16px; +} + +body.dark .post-single--press .post-description { + color: #afc1ff; +} + +.cn1-press-tabs { + display: inline-flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 18px; + border-bottom: 1px solid rgba(28, 81, 255, 0.24); + padding-bottom: 8px; +} + +.cn1-press-tabs__btn { + border: 0; + border-radius: 8px; + padding: 8px 14px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + background: rgba(28, 81, 255, 0.1); + color: #1c51ff; +} + +.cn1-press-tabs__btn.is-active { + background: #1c51ff; + color: #f5f8ff; +} + +body.dark .cn1-press-tabs { + border-bottom-color: rgba(175, 193, 255, 0.3); +} + +body.dark .cn1-press-tabs__btn { + background: rgba(175, 193, 255, 0.14); + color: #afc1ff; +} + +body.dark .cn1-press-tabs__btn.is-active { + background: #1d52ff; + color: #f5f8ff; +} + +.cn1-press-panel { + padding-top: 6px; +} + +.cn1-press-list { + display: grid; + gap: 16px; +} + +.cn1-press-item { + display: grid; + grid-template-columns: 190px 1fr; + gap: 18px; + align-items: start; + padding: 14px 0 18px; + border-bottom: 1px solid rgba(28, 81, 255, 0.16); +} + +body.dark .cn1-press-item { + border-bottom-color: rgba(175, 193, 255, 0.15); +} + +.cn1-press-item__logo-wrap { + min-height: 82px; + display: flex; + align-items: center; +} + +.cn1-press-item__logo { + max-width: 180px; + max-height: 76px; + width: auto; + height: auto; + object-fit: contain; +} + +.cn1-press-item__quote, +.cn1-press-item__headline { + margin: 0 0 8px; + color: #25345a; + line-height: 1.5; +} + +.cn1-press-item__headline { + font-weight: 600; +} + +.cn1-press-item__source { + margin: 0 0 10px; + color: #1c51ff; + font-weight: 600; + font-size: 14px; +} + +body.dark .cn1-press-item__quote, +body.dark .cn1-press-item__headline { + color: #e3ebff; +} + +body.dark .cn1-press-item__source { + color: #afc1ff; +} + +.cn1-press-item__links { + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.cn1-press-item__links a { + display: inline-flex; + align-items: center; + gap: 6px; + color: #1c51ff; + font-size: 13px; + font-weight: 600; + text-decoration: none; +} + +.cn1-press-item__links i { + width: 20px; + height: 20px; + border-radius: 999px; + border: 1px solid rgba(28, 81, 255, 0.55); + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 10px; +} + +body.dark .cn1-press-item__links a { + color: #afc1ff; +} + +body.dark .cn1-press-item__links i { + border-color: rgba(175, 193, 255, 0.55); +} + +.cn1-release-list { + display: grid; + gap: 16px; +} + +.cn1-release-item { + display: grid; + grid-template-columns: 64px 1fr; + gap: 16px; + align-items: center; + padding: 14px 0; + border-bottom: 1px solid rgba(28, 81, 255, 0.16); +} + +body.dark .cn1-release-item { + border-bottom-color: rgba(175, 193, 255, 0.15); +} + +.cn1-release-item__icon img { + width: 52px; + height: 52px; +} + +.cn1-release-item__body h3 { + margin: 0 0 6px; + font-size: 19px; +} + +.cn1-release-item__body h3 a { + color: #1f2e59; + text-decoration: none; +} + +.cn1-release-item__body h3 a:hover { + color: #1c51ff; +} + +.cn1-release-item__body p { + margin: 0; + color: #536082; + font-size: 14px; +} + +body.dark .cn1-release-item__body h3 a { + color: #f5f8ff; +} + +body.dark .cn1-release-item__body h3 a:hover { + color: #afc1ff; +} + +body.dark .cn1-release-item__body p { + color: #afc1ff; +} + +.cn1-press-kit h2 { + margin: 0 0 8px; + font-size: 28px; +} + +.cn1-press-kit > p { + margin: 0 0 16px; + color: #556285; +} + +body.dark .cn1-press-kit > p { + color: #afc1ff; +} + +.cn1-press-kit__grid { + display: grid; + grid-template-columns: 240px 1fr; + gap: 0; + border: 1px solid rgba(28, 81, 255, 0.22); + border-radius: 10px; + overflow: hidden; +} + +body.dark .cn1-press-kit__grid { + border-color: rgba(175, 193, 255, 0.28); +} + +.cn1-press-kit__label, +.cn1-press-kit__value { + padding: 14px; + border-bottom: 1px solid rgba(28, 81, 255, 0.12); +} + +.cn1-press-kit__label { + font-size: 14px; + font-weight: 700; + color: #1c51ff; + background: rgba(28, 81, 255, 0.06); +} + +.cn1-press-kit__value { + color: #2f3a61; +} + +.cn1-press-kit__value p { + margin: 0 0 6px; +} + +.cn1-press-kit__value p:last-child { + margin-bottom: 0; +} + +body.dark .cn1-press-kit__label, +body.dark .cn1-press-kit__value { + border-bottom-color: rgba(175, 193, 255, 0.16); +} + +body.dark .cn1-press-kit__label { + color: #afc1ff; + background: rgba(175, 193, 255, 0.09); +} + +body.dark .cn1-press-kit__value { + color: #f5f8ff; +} + +.cn1-press-kit__download { + display: inline-flex; + align-items: center; + gap: 8px; + color: #1c51ff; + font-weight: 600; + text-decoration: none; +} + +body.dark .cn1-press-kit__download { + color: #afc1ff; +} + +@media (max-width: 920px) { + .cn1-press-item { + grid-template-columns: 1fr; + gap: 10px; + } + + .cn1-press-item__logo-wrap { + min-height: 0; + } + + .cn1-press-kit__grid { + grid-template-columns: 1fr; + } + + .cn1-press-kit__label, + .cn1-press-kit__value { + border-bottom: 0; + } + + .cn1-press-kit__label { + border-top: 1px solid rgba(28, 81, 255, 0.16); + } + + .cn1-press-kit__grid .cn1-press-kit__label:first-child { + border-top: 0; + } +} diff --git a/docs/website/assets/css/extended/cn1-pricing.css b/docs/website/assets/css/extended/cn1-pricing.css new file mode 100644 index 0000000000..cd470ea977 --- /dev/null +++ b/docs/website/assets/css/extended/cn1-pricing.css @@ -0,0 +1,325 @@ +.cn1-pricing-page { + max-width: 1200px; + color: #f5f8ff; +} + +body:not(.dark) .cn1-pricing-page { + color: #1a2c57; +} + +.cn1-pricing-header { + text-align: center; +} + +.cn1-pricing-subtitle { + margin: 0.35rem 0 0; + color: #afc1ff; + font-size: 1.05rem; + font-weight: 500; +} + +.cn1-pricing-note { + margin: 0.45rem 0 0; + color: rgba(245, 248, 255, 0.78); + font-size: 0.92rem; +} + +body:not(.dark) .cn1-pricing-subtitle { + color: #1d52ff; +} + +body:not(.dark) .cn1-pricing-note { + color: #536184; +} + +.cn1-pricing-toggle { + margin: 1.35rem auto 1rem; + padding: 0.9rem 1rem; + display: grid; + gap: 0.6rem; + justify-items: center; +} + +body:not(.dark) .cn1-pricing-toggle { + background: transparent; +} + +.cn1-pricing-toggle__label { + font-size: 0.8rem; + letter-spacing: 0.08em; + text-transform: uppercase; + color: #afc1ff; + font-weight: 600; +} + +body:not(.dark) .cn1-pricing-toggle__label { + color: #1d52ff; +} + +.cn1-pricing-toggle__switch { + display: inline-flex; + border: 1px solid rgba(175, 193, 255, 0.35); + border-radius: 2px; + padding: 0.2rem; + background: rgba(8, 17, 55, 0.25); +} + +body:not(.dark) .cn1-pricing-toggle__switch { + background: #fff; + border-color: #d0dcff; +} + +.cn1-pricing-toggle__switch button { + border: 0; + background: transparent; + color: rgba(245, 248, 255, 0.78); + font-family: "Poppins", sans-serif; + font-size: 0.86rem; + font-weight: 600; + padding: 0.4rem 0.9rem; + border-radius: 2px; + cursor: pointer; +} + +body:not(.dark) .cn1-pricing-toggle__switch button { + color: #4d5b85; +} + +.cn1-pricing-toggle__switch button.is-active { + background: #1d52ff; + color: #f5f8ff; +} + +.cn1-pricing-toggle__hint { + margin: 0; + font-size: 0.82rem; + color: rgba(245, 248, 255, 0.72); + text-align: center; +} + +body:not(.dark) .cn1-pricing-toggle__hint { + color: #627199; +} + +.cn1-pricing-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 0.9rem; + align-items: stretch; +} + +.cn1-price-card { + border: 1px solid rgba(29, 82, 255, 0.45); + border-radius: 2px; + background: rgba(62, 74, 112, 0.38); + padding: 1rem; + display: flex; + flex-direction: column; +} + +body:not(.dark) .cn1-price-card { + background: #f5f8ff; + border-color: #d8e2ff; +} + +.cn1-price-card--featured { + border-color: #1d52ff; + box-shadow: 0 12px 30px rgba(5, 15, 54, 0.25); +} + +body:not(.dark) .cn1-price-card--featured { + box-shadow: 0 10px 24px rgba(19, 70, 209, 0.12); +} + +.cn1-price-card header { + margin-bottom: 0.8rem; +} + +.cn1-price-card__badge { + margin: 0 0 0.35rem; + display: inline-block; + font-size: 0.7rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.08em; + background: #1d52ff; + color: #f5f8ff; + border-radius: 2px; + padding: 0.2rem 0.45rem; +} + +.cn1-price-card__tier { + margin: 0; + font-size: 1.2rem; + font-weight: 700; + color: #f5f8ff; +} + +body:not(.dark) .cn1-price-card__tier { + color: #102154; +} + +.cn1-price-card__price { + margin: 0.35rem 0 0; + font-size: 0.9rem; + color: rgba(245, 248, 255, 0.9); +} + +.cn1-price-card__price span { + font-size: 1.65rem; + font-weight: 800; + color: #f5f8ff; +} + +body:not(.dark) .cn1-price-card__price, +body:not(.dark) .cn1-price-card__price span { + color: #132b63; +} + +.cn1-price-card__bill { + margin: 0.2rem 0 0; + color: #afc1ff; + font-size: 0.78rem; + min-height: 2.1em; +} + +body:not(.dark) .cn1-price-card__bill { + color: #2e55c4; +} + +.cn1-price-card ul { + list-style: none; + padding: 0; + margin: 0.2rem 0 0.95rem; + display: grid; + gap: 0.45rem; +} + +.cn1-price-card li { + position: relative; + padding-left: 1rem; + color: rgba(245, 248, 255, 0.9); + font-size: 0.86rem; + line-height: 1.35; +} + +.cn1-price-card li::before { + content: ""; + position: absolute; + left: 0; + top: 0.5em; + width: 0.35rem; + height: 0.35rem; + border-radius: 50%; + background: #1d52ff; +} + +body:not(.dark) .cn1-price-card li { + color: #2d3c66; +} + +.cn1-price-card__cta { + margin-top: auto; + text-align: center; + text-decoration: none; + border: 1px solid rgba(245, 248, 255, 0.75); + color: #f5f8ff; + border-radius: 2px; + padding: 0.55rem 0.7rem; + font-weight: 600; + font-size: 0.9rem; + appearance: none; + background: transparent; + cursor: pointer; + width: 100%; + font-family: "Poppins", sans-serif; + line-height: 1.2; +} + +.cn1-price-card__cta:hover { + background: rgba(29, 82, 255, 0.2); + border-color: #1d52ff; +} + +body:not(.dark) .cn1-price-card__cta { + color: #16316c; + border-color: #bfd0ff; +} + +body:not(.dark) .cn1-price-card__cta:hover { + background: #edf2ff; +} + +.cn1-pricing-faq { + margin-top: 2rem; + padding: 0.2rem 0 0; +} + +body:not(.dark) .cn1-pricing-faq { + background: transparent; +} + +.cn1-pricing-faq h2, +.cn1-pricing-faq h3 { + margin-top: 1rem; +} + +body:not(.dark) .cn1-pricing-faq h2, +body:not(.dark) .cn1-pricing-faq h3, +body:not(.dark) .cn1-pricing-faq p, +body:not(.dark) .cn1-pricing-faq li, +body:not(.dark) .cn1-pricing-faq strong { + color: #203362; +} + +body:not(.dark) .cn1-pricing-faq a { + color: #1d52ff; +} + +.cn1-pricing-page .cn1-loved { + margin-top: 2rem; + padding-left: 0; + padding-right: 0; +} + +body:not(.dark) .cn1-pricing-page .cn1-loved h2 { + color: #1d52ff; +} + +body:not(.dark) .cn1-pricing-page .cn1-loved__grid > img { + opacity: 1; + filter: none; +} + +body:not(.dark) .cn1-pricing-page .cn1-loved__grid .cn1-carousel__slide blockquote { + color: #1b274e; + background: #e7ecfb; + border-color: #2b66ea; +} + +body:not(.dark) .cn1-pricing-page .cn1-loved__grid .cn1-carousel__slide blockquote span + span { + color: #4a5f97; +} + +body:not(.dark) .cn1-pricing-page .cn1-loved__grid .cn1-carousel__slide blockquote::after { + background: #e7ecfb; + border-right-color: #2b66ea; + border-bottom-color: #2b66ea; +} + +body:not(.dark) .cn1-pricing-page .cn1-loved__grid .cn1-carousel__slide h3, +body:not(.dark) .cn1-pricing-page .cn1-loved__grid .cn1-carousel__slide p { + color: #1b274e; +} + +@media (max-width: 1120px) { + .cn1-pricing-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 700px) { + .cn1-pricing-grid { + grid-template-columns: 1fr; + } +} diff --git a/docs/website/assets/css/extended/cn1-search.css b/docs/website/assets/css/extended/cn1-search.css new file mode 100644 index 0000000000..b04d77df19 --- /dev/null +++ b/docs/website/assets/css/extended/cn1-search.css @@ -0,0 +1,96 @@ +.cn1-menu-search-link { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 1.05rem; + line-height: 1; + min-width: 1.25rem; +} + +.cn1-search-shell { + border: 1px solid rgba(29, 82, 255, 0.35); + border-radius: 14px; + padding: 1rem; + background: rgba(68, 82, 123, 0.22); +} + +body.light .cn1-search-shell { + background: #f5f8ff; + border-color: #d7e2ff; +} + +.cn1-search-label { + display: block; + font-size: 0.86rem; + font-weight: 600; + margin-bottom: 0.35rem; + color: var(--cn1-course-link, #afc1ff); +} + +.cn1-search-input { + width: 100%; + border: 1px solid rgba(175, 193, 255, 0.4); + border-radius: 10px; + padding: 0.75rem 0.85rem; + background: rgba(8, 17, 55, 0.5); + color: #f5f8ff; + font-family: "Poppins", sans-serif; + font-size: 0.98rem; +} + +body.light .cn1-search-input { + background: #fff; + color: #1c2a55; + border-color: #c9d6ff; +} + +.cn1-search-status { + margin: 0.7rem 0 0; + font-size: 0.86rem; + color: var(--cn1-course-soft-text, rgba(217, 228, 255, 0.85)); +} + +.cn1-search-results { + margin-top: 0.9rem; + display: grid; + gap: 0.75rem; +} + +.cn1-search-result { + border: 1px solid rgba(175, 193, 255, 0.25); + border-radius: 10px; + padding: 0.75rem 0.8rem; + background: rgba(8, 17, 55, 0.22); +} + +body.light .cn1-search-result { + background: rgba(255, 255, 255, 0.75); + border-color: #d7e2ff; +} + +.cn1-search-result h2 { + margin: 0; + font-size: 1rem; +} + +.cn1-search-result h2 a { + color: var(--cn1-course-link-strong, #f5f8ff); + text-decoration: none; +} + +.cn1-search-result h2 a:hover { + color: var(--cn1-course-link, #afc1ff); +} + +.cn1-search-result p { + margin: 0.4rem 0; + font-size: 0.9rem; + line-height: 1.45; + color: var(--cn1-course-soft-text, rgba(217, 228, 255, 0.85)); +} + +.cn1-search-result__url { + font-size: 0.8rem; + text-decoration: none; + color: var(--cn1-course-link, #afc1ff); +} diff --git a/docs/website/assets/css/extended/cn1-team.css b/docs/website/assets/css/extended/cn1-team.css new file mode 100644 index 0000000000..296a7ce713 --- /dev/null +++ b/docs/website/assets/css/extended/cn1-team.css @@ -0,0 +1,60 @@ +.post-single--team .post-content > h2 { + margin-top: 0.3rem; + margin-bottom: 1rem; +} + +.post-single--team .post-content > h3 { + margin-top: 1.4rem; + margin-bottom: 0.55rem; + padding: 0.6rem 0.8rem; + border-left: 4px solid #1d52ff; + border-radius: 10px; + background: rgba(29, 82, 255, 0.08); +} + +body.dark .post-single--team .post-content > h3 { + border-left-color: #afc1ff; + background: rgba(175, 193, 255, 0.12); +} + +.post-single--team .post-content > p > img { + width: 120px; + height: 120px; + border-radius: 50%; + object-fit: cover; + border: 2px solid rgba(29, 82, 255, 0.4); + float: right; + margin: 0.1rem 0 0.7rem 1rem; +} + +body.dark .post-single--team .post-content > p > img { + border-color: rgba(175, 193, 255, 0.5); +} + +.post-single--team .post-content > ul { + margin-top: 0.55rem; + margin-bottom: 1.2rem; +} + +.post-single--team .post-content > hr { + margin: 1.2rem 0 1rem; + border-color: rgba(29, 82, 255, 0.22); +} + +body.dark .post-single--team .post-content > hr { + border-color: rgba(175, 193, 255, 0.25); +} + +.post-single--team .post-content::after { + content: ""; + display: block; + clear: both; +} + +@media (max-width: 760px) { + .post-single--team .post-content > p > img { + float: none; + display: block; + margin: 0.25rem auto 0.8rem; + } +} diff --git a/docs/website/assets/css/extended/cn1-videos.css b/docs/website/assets/css/extended/cn1-videos.css new file mode 100644 index 0000000000..9060f57220 --- /dev/null +++ b/docs/website/assets/css/extended/cn1-videos.css @@ -0,0 +1,133 @@ +.post-single--videos { + font-family: "Poppins", sans-serif; +} + +.post-single--videos .post-description { + margin: 0; + color: #556285; +} + +body.dark .post-single--videos .post-description { + color: #afc1ff; +} + +.cn1-videos-hero { + margin: 22px 0 20px; + padding: 18px 20px; + border: 1px solid rgba(28, 81, 255, 0.2); + border-radius: 12px; + background: linear-gradient(145deg, rgba(28, 81, 255, 0.08), rgba(28, 81, 255, 0.03)); +} + +body.dark .cn1-videos-hero { + border-color: rgba(175, 193, 255, 0.25); + background: linear-gradient(145deg, rgba(175, 193, 255, 0.13), rgba(175, 193, 255, 0.06)); +} + +.cn1-videos-hero__eyebrow { + margin: 0 0 6px; + color: #1c51ff; + font-size: 12px; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +body.dark .cn1-videos-hero__eyebrow { + color: #afc1ff; +} + +.cn1-videos-hero h2 { + margin: 0; + font-size: 28px; + line-height: 1.22; +} + +.cn1-videos-hero p { + margin: 10px 0 0; + color: #334371; + line-height: 1.55; +} + +body.dark .cn1-videos-hero p { + color: #dce5ff; +} + +.cn1-videos-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 18px; +} + +.cn1-video-card { + border: 1px solid rgba(28, 81, 255, 0.18); + border-radius: 12px; + overflow: hidden; + background: rgba(255, 255, 255, 0.76); +} + +body.dark .cn1-video-card { + border-color: rgba(175, 193, 255, 0.2); + background: rgba(10, 24, 70, 0.85); +} + +.cn1-video-card__embed { + position: relative; + aspect-ratio: 16 / 9; + width: 100%; + background: #121722; +} + +.cn1-video-card__embed iframe { + width: 100%; + height: 100%; + border: 0; + display: block; +} + +.cn1-video-card__meta { + padding: 14px 14px 16px; +} + +.cn1-video-card__index { + margin: 0 0 6px; + font-size: 11px; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + color: #1c51ff; +} + +body.dark .cn1-video-card__index { + color: #afc1ff; +} + +.cn1-video-card__meta h3 { + margin: 0 0 12px; + font-size: 19px; + line-height: 1.35; +} + +.cn1-video-card__meta a { + display: inline-flex; + align-items: center; + gap: 8px; + font-size: 13px; + font-weight: 600; + color: #1c51ff; + text-decoration: none; +} + +body.dark .cn1-video-card__meta a { + color: #afc1ff; +} + +@media (max-width: 760px) { + .cn1-videos-grid { + grid-template-columns: 1fr; + } + + .cn1-videos-hero h2 { + font-size: 23px; + } +} diff --git a/docs/website/assets/js/cn1-crisp.js b/docs/website/assets/js/cn1-crisp.js new file mode 100644 index 0000000000..9e71d9ebf1 --- /dev/null +++ b/docs/website/assets/js/cn1-crisp.js @@ -0,0 +1,135 @@ +(() => { + const CONSENT_KEY = "cn1-crisp-consent-v1"; + const CONSENT_COOKIE = "cn1_crisp_consent"; + const WEBSITE_ID = "e0201fca-1e59-4f30-9d00-8c37aa18293e"; + const CONSENT_TTL_DAYS = 365; + + const readCookie = (name) => { + const prefix = `${name}=`; + const found = document.cookie + .split(";") + .map((part) => part.trim()) + .find((part) => part.startsWith(prefix)); + return found ? decodeURIComponent(found.substring(prefix.length)) : null; + }; + + const writeCookie = (name, value, days) => { + const expires = new Date(Date.now() + days * 24 * 60 * 60 * 1000).toUTCString(); + document.cookie = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/; SameSite=Lax`; + }; + + const getConsent = () => { + const cookieValue = readCookie(CONSENT_COOKIE); + if (cookieValue === "accepted" || cookieValue === "declined") { + return cookieValue; + } + try { + const storageValue = localStorage.getItem(CONSENT_KEY); + if (storageValue === "accepted" || storageValue === "declined") { + return storageValue; + } + } catch (e) { + // no-op + } + return null; + }; + + const setConsent = (value) => { + writeCookie(CONSENT_COOKIE, value, CONSENT_TTL_DAYS); + try { + localStorage.setItem(CONSENT_KEY, value); + } catch (e) { + // no-op + } + }; + + const loadCrisp = () => { + if (window.CRISP_WEBSITE_ID || document.getElementById("cn1-crisp-loader")) { + return; + } + window.$crisp = window.$crisp || []; + window.CRISP_WEBSITE_ID = WEBSITE_ID; + const d = document; + const s = d.createElement("script"); + s.id = "cn1-crisp-loader"; + s.src = "https://client.crisp.chat/l.js"; + s.async = true; + d.head.appendChild(s); + }; + + const hideCrisp = () => { + window.$crisp = window.$crisp || []; + try { + window.$crisp.push(["do", "chat:hide"]); + } catch (e) { + // no-op + } + const crispNode = document.querySelector(".crisp-client"); + if (crispNode) { + crispNode.style.display = "none"; + } + }; + + const banner = document.querySelector("[data-cn1-cookie-banner]"); + const acceptBtn = document.querySelector("[data-cn1-cookie-accept]"); + const declineBtn = document.querySelector("[data-cn1-cookie-decline]"); + + const closeBanner = () => { + if (banner) { + banner.setAttribute("hidden", "hidden"); + banner.style.display = "none"; + } + }; + + const openBanner = () => { + if (banner) { + banner.removeAttribute("hidden"); + banner.style.display = "flex"; + } + }; + + const acceptConsent = () => { + setConsent("accepted"); + closeBanner(); + loadCrisp(); + }; + + const declineConsent = () => { + setConsent("declined"); + closeBanner(); + hideCrisp(); + }; + + const consent = getConsent(); + if (consent === "accepted") { + loadCrisp(); + closeBanner(); + } else if (consent === "declined") { + hideCrisp(); + closeBanner(); + } else { + openBanner(); + } + + if (acceptBtn) { + acceptBtn.addEventListener("click", acceptConsent); + } + + if (declineBtn) { + declineBtn.addEventListener("click", declineConsent); + } + + document.querySelectorAll("[data-cn1-enable-chat]").forEach((link) => { + link.addEventListener("click", (event) => { + event.preventDefault(); + acceptConsent(); + }); + }); + + document.querySelectorAll("[data-cn1-manage-chat]").forEach((link) => { + link.addEventListener("click", (event) => { + event.preventDefault(); + openBanner(); + }); + }); +})(); diff --git a/docs/website/assets/js/cn1-demo.js b/docs/website/assets/js/cn1-demo.js new file mode 100644 index 0000000000..3401830c7a --- /dev/null +++ b/docs/website/assets/js/cn1-demo.js @@ -0,0 +1,42 @@ +(() => { + const carousels = document.querySelectorAll("[data-cn1-demo-carousel]"); + carousels.forEach((root) => { + const track = root.querySelector("[data-cn1-demo-track]"); + const slides = Array.from(root.querySelectorAll("[data-cn1-demo-slide]")); + const dots = Array.from(root.querySelectorAll("[data-cn1-demo-dot]")); + const prev = root.querySelector("[data-cn1-demo-prev]"); + const next = root.querySelector("[data-cn1-demo-next]"); + if (!track || slides.length <= 1) return; + + let index = 0; + + const render = () => { + track.style.transform = `translateX(-${index * 100}%)`; + dots.forEach((dot, i) => { + dot.setAttribute("aria-current", i === index ? "true" : "false"); + }); + }; + + const go = (value) => { + const max = slides.length - 1; + index = Math.max(0, Math.min(max, value)); + render(); + }; + + const step = (delta) => { + const max = slides.length - 1; + let nextIndex = index + delta; + if (nextIndex < 0) nextIndex = max; + if (nextIndex > max) nextIndex = 0; + go(nextIndex); + }; + + prev?.addEventListener("click", () => step(-1)); + next?.addEventListener("click", () => step(1)); + dots.forEach((dot, i) => { + dot.addEventListener("click", () => go(i)); + }); + + render(); + }); +})(); diff --git a/docs/website/assets/js/cn1-home.js b/docs/website/assets/js/cn1-home.js new file mode 100644 index 0000000000..db83089b3e --- /dev/null +++ b/docs/website/assets/js/cn1-home.js @@ -0,0 +1,73 @@ +(() => { + const isHome = !!document.querySelector(".cn1-hero"); + if (isHome) { + document.body.classList.add("cn1-homepage"); + + const accordions = document.querySelectorAll(".cn1-accordion"); + accordions.forEach((accordion) => { + const items = Array.from(accordion.querySelectorAll(".cn1-acc-item")); + const setState = (item, open) => { + const trigger = item.querySelector(".cn1-acc-trigger"); + const panel = item.querySelector(".cn1-acc-panel"); + if (!trigger || !panel) return; + item.classList.toggle("is-open", open); + trigger.setAttribute("aria-expanded", open ? "true" : "false"); + panel.style.maxHeight = open ? panel.scrollHeight + "px" : "0px"; + const icon = trigger.querySelector(".cn1-acc-caret i"); + if (icon) { + icon.classList.toggle("fa-chevron-down", open); + icon.classList.toggle("fa-chevron-right", !open); + } + }; + + items.forEach((item) => setState(item, item.classList.contains("is-open"))); + accordion.addEventListener("click", (event) => { + const trigger = event.target.closest(".cn1-acc-trigger"); + if (!trigger) return; + const item = trigger.closest(".cn1-acc-item"); + if (!item) return; + const willOpen = !item.classList.contains("is-open"); + items.forEach((it) => setState(it, false)); + setState(item, willOpen); + }); + }); + } + + const carousels = document.querySelectorAll(".cn1-carousel[data-carousel]"); + carousels.forEach((carousel) => { + const track = carousel.querySelector(".cn1-carousel__track"); + const slides = Array.from(carousel.querySelectorAll(".cn1-carousel__slide")); + const dotsWrap = carousel.querySelector(".cn1-carousel__dots"); + const prev = carousel.querySelector(".cn1-carousel__prev"); + const next = carousel.querySelector(".cn1-carousel__next"); + if (!track || slides.length === 0) return; + + let current = slides.findIndex((s) => s.classList.contains("is-active")); + if (current < 0) current = 0; + + const setSlide = (index) => { + current = (index + slides.length) % slides.length; + slides.forEach((slide, i) => slide.classList.toggle("is-active", i === current)); + track.style.transform = `translateX(${-100 * current}%)`; + if (dotsWrap) { + dotsWrap.querySelectorAll("button").forEach((dot, i) => { + dot.classList.toggle("is-active", i === current); + dot.setAttribute("aria-current", i === current ? "true" : "false"); + }); + } + }; + + if (dotsWrap) { + dotsWrap.innerHTML = slides + .map((_, i) => ``) + .join(""); + dotsWrap.querySelectorAll("button").forEach((dot, i) => { + dot.addEventListener("click", () => setSlide(i)); + }); + } + + if (prev) prev.addEventListener("click", () => setSlide(current - 1)); + if (next) next.addEventListener("click", () => setSlide(current + 1)); + setSlide(current); + }); +})(); diff --git a/docs/website/assets/js/cn1-pricing.js b/docs/website/assets/js/cn1-pricing.js new file mode 100644 index 0000000000..32c7c00bbf --- /dev/null +++ b/docs/website/assets/js/cn1-pricing.js @@ -0,0 +1,59 @@ +(() => { + const root = document.querySelector("[data-billing-toggle]"); + const signupLinks = Array.from(document.querySelectorAll("[data-signup-link][data-level]")); + if (!root && signupLinks.length === 0) return; + + const buttons = root ? Array.from(root.querySelectorAll("[data-billing]")) : []; + const hint = root ? root.querySelector("[data-billing-hint]") : null; + const cards = Array.from(document.querySelectorAll(".cn1-price-card[data-plan]")); + const buildSignupUrl = (level, mode) => + `https://cloud.codenameone.com/secure/signup?level=${encodeURIComponent(level)}&mode=${encodeURIComponent(mode)}`; + + const update = (mode) => { + if (root) { + root.dataset.billingMode = mode; + } + + buttons.forEach((btn) => { + const active = btn.dataset.billing === mode; + btn.classList.toggle("is-active", active); + btn.setAttribute("aria-selected", active ? "true" : "false"); + }); + + cards.forEach((card) => { + const priceNode = card.querySelector("[data-price]"); + const billNode = card.querySelector("[data-bill]"); + const monthly = card.dataset.monthly; + const annualMonthly = card.dataset.annualMonthly; + const annualTotal = card.dataset.annualTotal; + + if (!priceNode || !billNode) return; + + if (mode === "annual") { + priceNode.textContent = annualMonthly; + billNode.textContent = `Billed annually at $${annualTotal}/year`; + } else { + priceNode.textContent = monthly; + billNode.textContent = "Billed monthly"; + } + }); + + signupLinks.forEach((link) => { + const level = (link.dataset.level || "").toLowerCase(); + if (!level) return; + link.href = buildSignupUrl(level, mode); + }); + + if (hint) { + hint.textContent = mode === "annual" + ? "Annual billing selected. Prices shown are monthly equivalents with yearly billing." + : "Monthly billing selected. Switch to annual to lower the monthly equivalent."; + } + }; + + buttons.forEach((btn) => { + btn.addEventListener("click", () => update(btn.dataset.billing)); + }); + + update("monthly"); +})(); diff --git a/docs/website/assets/js/cn1-site.js b/docs/website/assets/js/cn1-site.js new file mode 100644 index 0000000000..fbad3fb681 --- /dev/null +++ b/docs/website/assets/js/cn1-site.js @@ -0,0 +1,140 @@ +(() => { + const path = window.location.pathname || ""; + const isBlogPath = path === "/blog/" || path.startsWith("/blog/"); + if (isBlogPath) { + document.body.classList.add("cn1-blog-post"); + } + + const mobileMq = window.matchMedia("(max-width: 980px)"); + const header = document.querySelector(".cn1-header"); + if (header) { + const items = Array.from(header.querySelectorAll("#menu > li.has-children")); + const navToggle = header.querySelector("#cn1-nav-toggle"); + + const closeAll = () => { + items.forEach((item) => { + item.classList.remove("open"); + const trigger = item.querySelector(".cn1-menu-trigger"); + if (trigger) trigger.setAttribute("aria-expanded", "false"); + }); + }; + + items.forEach((item) => { + const trigger = item.querySelector(".cn1-menu-trigger"); + if (!trigger) return; + trigger.addEventListener("click", (event) => { + if (!mobileMq.matches) return; + event.preventDefault(); + const willOpen = !item.classList.contains("open"); + closeAll(); + if (willOpen) { + item.classList.add("open"); + trigger.setAttribute("aria-expanded", "true"); + } + }); + }); + + if (navToggle) { + navToggle.addEventListener("change", () => { + if (!navToggle.checked) closeAll(); + }); + } + + const resetDesktop = () => { + if (!mobileMq.matches) closeAll(); + }; + + if (mobileMq.addEventListener) { + mobileMq.addEventListener("change", resetDesktop); + } else if (mobileMq.addListener) { + mobileMq.addListener(resetDesktop); + } + + const onScroll = () => { + header.classList.toggle("cn1-header--compact", window.scrollY > 36); + }; + onScroll(); + window.addEventListener("scroll", onScroll, { passive: true }); + } + + const updateThemeUi = () => { + const dark = document.body.classList.contains("dark"); + const label = dark ? "Switch to Light Mode" : "Switch to Dark Mode"; + document.querySelectorAll("[data-cn1-theme-toggle]").forEach((el) => { + el.setAttribute("aria-label", label); + el.setAttribute("title", label); + }); + }; + + const toggleTheme = () => { + const dark = document.body.classList.contains("dark"); + if (dark) { + document.body.classList.remove("dark"); + localStorage.setItem("pref-theme", "light"); + } else { + document.body.classList.add("dark"); + localStorage.setItem("pref-theme", "dark"); + } + updateThemeUi(); + }; + + const pref = localStorage.getItem("pref-theme"); + if (pref === "dark") { + document.body.classList.add("dark"); + } else if (pref === "light") { + document.body.classList.remove("dark"); + } + + document.querySelectorAll("[data-cn1-theme-toggle]").forEach((button) => { + button.addEventListener("click", toggleTheme); + }); + + const observer = new MutationObserver(updateThemeUi); + observer.observe(document.body, { attributes: true, attributeFilter: ["class"] }); + updateThemeUi(); + + const scheme = window.matchMedia("(prefers-color-scheme: dark)"); + if (scheme.addEventListener) { + scheme.addEventListener("change", updateThemeUi); + } else if (scheme.addListener) { + scheme.addListener(updateThemeUi); + } + + document.querySelectorAll("[data-cn1-tabs]").forEach((tabs) => { + const triggers = Array.from(tabs.querySelectorAll("[data-cn1-tab-trigger]")); + if (!triggers.length) return; + const scope = tabs.closest("article, section, main, body") || document; + const panels = triggers + .map((trigger) => + scope.querySelector( + `[data-cn1-tab-panel="${trigger.getAttribute("data-cn1-tab-trigger")}"]` + ) + ) + .filter(Boolean); + + const setActive = (name) => { + triggers.forEach((trigger) => { + const active = trigger.getAttribute("data-cn1-tab-trigger") === name; + trigger.classList.toggle("is-active", active); + }); + panels.forEach((panel) => { + const active = panel.getAttribute("data-cn1-tab-panel") === name; + panel.classList.toggle("is-active", active); + panel.hidden = !active; + }); + }; + + triggers.forEach((trigger) => { + trigger.addEventListener("click", () => { + setActive(trigger.getAttribute("data-cn1-tab-trigger")); + }); + }); + + const initial = tabs.querySelector("[data-cn1-tab-trigger].is-active"); + setActive( + (initial && initial.getAttribute("data-cn1-tab-trigger")) || + triggers[0].getAttribute("data-cn1-tab-trigger") + ); + }); + +})(); diff --git a/docs/website/content/about-us.md b/docs/website/content/about-us.md new file mode 100644 index 0000000000..e50c977467 --- /dev/null +++ b/docs/website/content/about-us.md @@ -0,0 +1,51 @@ +--- +title: "About Us - What is Codename One and how Does it work?" +date: 2019-05-18 +slug: "about-us" +--- + +Learn more about Codename One and getting started resources. + +### What is Codename One? + +Codename One allows Java developers to write their mobile apps using Java or Kotlin. It generates native OS binaries that you can upload to Apple/Google/Microsoft etc. + +Codename One was founded by ex-Sun/Oracle mobile developers based on an open source project started back in 2007 within Sun Microsystems. The core vision of Codename One is to actualize the WORA (Write Once Run Anywhere) mantra of Java in the age of mobile devices. + +To enable that vision Codename One created a one of a kind industry leading set of tools that allow Java developers to build native mobile OS applications with a single code base. + +Codename One works with all major Java developer environments (IDE's) NetBeans, Eclipse, IntelliJ/IDEA or VSCode. + +https://youtu.be/rl6z7DD2-vg + +### How does Codename One work? + +To understand how Codename One works, its history etc. check the [developer guide](/manual/) (also available as a [PDF](/files/developer-guide.pdf)). It provide a birds eye view in the first chapter. + +You can also refer to [this stackoverflow answer](http://stackoverflow.com/questions/10639766/how-codename-one-works/10646336). There is a video that goes into further details [here](https://www.youtube.com/watch?v=MrwbpdMALig) (it's a bit long). + +The gist of this is that Codename One requires you to [obey some restrictions](/blog/why-we-dont-support-the-full-java-api.html) in the way you develop Java applications and use our plugin/API. Once you abide by those the Codename One tooling makes portability seamless. + +### How do Codename One Apps Look? + +They can look like anything, check out the [demos](/demos.html) section where you can see the diversity and some of the potential of Codename One apps. + +### Is Codename One Free? + +Codename One has a free version and paid versions. So yes & no. + +The base product is open source but our build system requires servers (Macs, Windows machines etc.) and we place a quota on their usage to prevent overuse which would deprive paying users from service. + +With the free version, there is a JAR size limit of 1 - 8.5mb. Notice that this is a very high limit as it applies only to your bytcode and not to the Codename One builtin API's and you can create pretty remarkable apps within this limit (all our demos fit within that limit). + +The free tier allows you to use your generated apps commercially and place have no restrictions on them. There are no nag screens or license limitations! + +There are many additional benefits and additional features you can get in the paid plans, see the [pricing details here](https://www.codenameone.com/pricing.html). + +### Where can I learn more? + +For more about Codename One [check out this post](/blog/tutorials-resources-learn-java-mobile-videos-courses-ios-android.html) covering the extensive set of tutorials/docs/videos. + +You can ask questions in [stackoverflow with the codenameone tag](http://stackoverflow.com/tags/codenameone) or you can also ask in the [discussion forum](/discussion-forum.html). Our engineers guarantee a response within 24 hours for such questions. + +Notice that Codename One assumes you already know Java so we don't have any tutorials for complete beginners. However, we do have some courses available at [Codename One Academy](https://codenameone.teachable.com/). diff --git a/docs/website/content/accepting-payments-with-zooz.md b/docs/website/content/accepting-payments-with-zooz.md new file mode 100644 index 0000000000..dca6c871f0 --- /dev/null +++ b/docs/website/content/accepting-payments-with-zooz.md @@ -0,0 +1,15 @@ +--- +title: "Accepting Payments With Zooz" +date: 2015-03-03 +slug: "accepting-payments-with-zooz" +--- + +# Accepting Payments With Zooz + +1. [Home](/) +2. [Monetization](/monetization.html) +3. Accepting Payments With Zooz + +To integrate with Zooz you need to register with them here and create a new application in their console. Make sure to create separate applications for iOS and Android since the keys can't be reused between the platforms. We will try to add HTML5 support for Blackberry in a future update. + +Once you did that the Codename One Payment API will seamlessly work with Zooz which is defined as a Manual payment provider and allows you to pay a fixed amount in a given currency. diff --git a/docs/website/content/advanced-build.md b/docs/website/content/advanced-build.md new file mode 100644 index 0000000000..a6128eeb96 --- /dev/null +++ b/docs/website/content/advanced-build.md @@ -0,0 +1,21 @@ +--- +title: "Advanced Build" +date: 2015-03-03 +slug: "advanced-build" +--- + +# Advanced Build + +Build hints/arguments allow us to manipulate the build process on the build servers + +1. [Home](/) +2. [Developers](https://beta.codenameone.com/getting-started.html) +3. Advanced Build + +## Sending Build Settings To The Server + +![Build Hints UI](/uploads/advanced_build.png) + +When sending a build to the server you can provide additional parameters to the build which will be incorporated into the build process on the server to hint on multiple different build time options.You can do this by right clicking the Codename One project and entering the project properties. There you will find the "Build Hints" tab in which you can just type the arguments and the appropriate values from the list below. + +We removed this page since it duplicates content from the developer guide and we should probably maintain only one **authoritative** list. The up to date list is [here](https://www.codenameone.com/manual/advanced-topics.html#_sending_arguments_to_the_build_server). diff --git a/docs/website/content/api.md b/docs/website/content/api.md new file mode 100644 index 0000000000..b1a7e3fefb --- /dev/null +++ b/docs/website/content/api.md @@ -0,0 +1,19 @@ +--- +title: "API" +date: 2015-03-03 +slug: "api" +--- + +# The Codename One API + +1. [Home](/) +2. Developers +3. API + +The Codename One Open Source API is a vast abstraction of mobile device platforms providing rich portable functionality. It leverages the highest feature set within devices (nicknamed: highest common denominator) to provide functionality smartphone owners are accustomed to. + +The API is mature and operator tested on a global scale, yet it is still rapidly evolving to meet the changing demands of the global market. You can browse the [javadoc API here](/javadoc/index.html), to get a sense of its depth and breadth. + +The API includes tremendous amount of functionality including rich and infinitely customizable UI components, as well as all device features from calls to camera, GPS etc. + +No API can cover all the bases all the time, which is why we provide native interfaces that allow you to embed any arbitrary operating system component or code right in the middle of any Codename One application. You can write native code in the platform specific language (Dalvik-Java for Android, Objective C for iOS etc.) and use that code to create a platform specific widget that can be embedded right into the Codename One component hierarchy without interfering with application flow. diff --git a/docs/website/content/app-gallery.md b/docs/website/content/app-gallery.md new file mode 100644 index 0000000000..858c20d8ed --- /dev/null +++ b/docs/website/content/app-gallery.md @@ -0,0 +1,15 @@ +--- +title: "App Gallery" +date: 2020-09-22 +slug: "app-gallery" +--- + +## coming Soon... + +## App Gallery + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Ut elit tellus, luctus nec ullamcorper mattis, +pulvinar dapibus leo. + +Go Back to Home page ![](/uploads/footer-logo.png) diff --git a/docs/website/content/architecture-of-the-gui-builder.md b/docs/website/content/architecture-of-the-gui-builder.md new file mode 100644 index 0000000000..a2d46d8d70 --- /dev/null +++ b/docs/website/content/architecture-of-the-gui-builder.md @@ -0,0 +1,91 @@ +--- +title: "Architecture Of The GUI Builder" +date: 2015-03-03 +slug: "architecture-of-the-gui-builder" +--- + +# Architecture Of The GUI Builder + +1. [Home](/) +2. Developers +3. Architecture Of The GUI Builder + +The Codename One GUI builder has several unique underlying concepts that aren't as common among such tools, in this article I will try to clarify some of these basic ideas. + +### Basic Concepts + +The Codename One Designer isn't a standard code generator, the UI is saved within the resource file and can be designed without the source files available. This has several advantages: + +1. No fragile generated code to break. +2. Designers who don't know Java can use the tool. +3. The "[Codename One LIVE!](http://www.codenameone.com/codename-one-live.html)" application can show a live preview of your design as you build it. +4. Images and theme settings can be integrated directly with the GUI without concern. +5. The tool is consistent since the file you save is the file you run. +6. GUI's/themes can be downloaded dynamically without replacing the application (this can reduce download size). +7. It allows for control over application flow. It allows preview within the tool without compilation. + +This does present some disadvantages and oddities: + +1. Its harder to integrate custom code into the GUI builder/designer tool. +2. The tool is somewhat opaque, there is no "code" you can inspect to see what was accomplished by the tool. +3. If the resource file grows too large it can significantly impact memory/performance of a running application. +4. Binding between code and GUI isn't as intuitive and is mostly centralized in a single class. + +In theory you don't need to generate any code, you can load any resource file that contains a UI element as you would normally load a Resource file: + +``` +Resources r = Resources.open("/myFile.res"); +``` + +Then you can just create a UI using the UIBuilder API: + +``` +UIBuilder u = new UIBuilder(); +Container c = u.createContainer(r, "uiNameInResource"); +``` + +(Notice that since Form & Dialog both derive from Container you can just downcast to the appropriate type). + +This would work for any resource file and can work completely dynamically! E.g. you can download a resource file on the fly and just show the UI that is within the resource file... That is what [Codename One LIVE!](http://www.codenameone.com/codename-one-live.html) is doing internally. + +### IDE Bindings + +While the option of creating a Resource file manually is powerful, its not nearly as convenient as modern GUI builders allow. Developers expect the ability to override events and basic behavior directly from the GUI builder and in mobile applications even the flow for some cases. + +To facilitate IDE integration we decided on using a single Statemachine class, similar to the common controller pattern. We considered multiple classes for every form/dialog/container and eventually decided this would make code generation more cumbersome. + +The designer effectively generates one class "StatemachineBase" which is a subclass of UIBuilder (you can change the name/package of the class in the Codename One properties file at the root of the project). StatemachineBase is generated every time the resource file is saved assuming that the resource file is within the src directory of a Codename One project. Since the state machine base class is always generated, all changes made into it will be overwritten without prompting the user. + +User code is placed within the Statemachine class, which is a subclass of the Statemachine Base class. Hence it is a subclass of UIBuilder! + +When the resource file is saved the designer generates 2 major types of methods into  Statemachine base: + +1. Finders - findX(Container c). A shortcut method to find a component instance within a hierarchy of containers. Effectively this is a shortcut syntax for [UIBuilder.findByName()](/javadoc/com/codename1/ui/util/UIBuilder.html#findByName%28java.lang.String,%20com.codename1.ui.Container%29), its still useful since the method is type safe. Hence if a resource component name is changed the find() method will fail in subsequent compilations. +2. Callback events - these are various callback methods with common names e.g.: onCreateFormX(), beforeFormX() etc. These will be invoked when a particular event/behavior occurs. + + Within the GUI builder, the event buttons would be enabled and the GUI builder provides a quick and dirty way to just override these methods. To prevent a future case in which the underlying resource file will be changed (e.g formX could be renamed to formY) a super method is invoked e.g. super.onCreateFormX(); + + This will probably be replaced with the @Override annotation when Java 5 features are integrated into Codename One. + +### Working With The Generated Code + +The generated code is rather simplistic, e.g. the following code from the tzone demo adds a for the remove button toggle: + + + +As you can see from the code above implementing some basic callbacks within the state machine is rather simple. The method findFriendsRoot(c.getParent()); is used to find the "FriendsRoot" component within the hierarchy, notice that we just pass the parent container to the finder method. If the finder method doesn't find the friend root under the parent it will find the "true" root component and search there. The friends root is a container that contains the full list of our "friends" and within it we can just work with the components that were instantiated by the GUI builder. Implementing Custom Components There are two basic approaches for custom components: + +1. Override a specific type - e.g. make all Form's derive a common base class. +2. Replace a deployed instance. + +The first  uses a feature of UIBuilder which allows overriding component types, specifically override [createComponentInstance](/javadoc/com/codename1/ui/util/UIBuilder.html#createComponentInstance%28java.lang.String,%20java.lang.Class%29) to return an instance of your desired component e.g.: + + + +This code allows me to create a unified global form subclass. That's very useful when I want so global system level functionality that isn't supported by the designer normally. + +The second approach allows me to replace an existing component: + + + +Notice that we replace the title with an empty label, in this case we do this so we can later replace it while animating the replace behavior thus creating a slide-in effect within the title. It can be replaced though, for every purpose including the purpose of a completely different custom made component. By using the replace method the existing layout constraints are automatically maintained. diff --git a/docs/website/content/archived-builds.md b/docs/website/content/archived-builds.md new file mode 100644 index 0000000000..836aec9316 --- /dev/null +++ b/docs/website/content/archived-builds.md @@ -0,0 +1,13 @@ +--- +title: "Archived Builds" +date: 2015-03-03 +slug: "archived-builds" +--- + +# Archived Builds + +1. [Home](/) +2. [Developers](https://beta.codenameone.com/getting-started.html) +3. Archived Builds + +This functionality was deprecated in recent versions and is no longer supported diff --git a/docs/website/content/blog/3-image-tools-for-app-marketing.md b/docs/website/content/blog/3-image-tools-for-app-marketing.md new file mode 100644 index 0000000000..c065d21cbe --- /dev/null +++ b/docs/website/content/blog/3-image-tools-for-app-marketing.md @@ -0,0 +1,89 @@ +--- +title: 3 Image Tools for App Marketing +slug: 3-image-tools-for-app-marketing +url: /blog/3-image-tools-for-app-marketing/ +original_url: https://www.codenameone.com/blog/3-image-tools-for-app-marketing.html +aliases: +- /blog/3-image-tools-for-app-marketing.html +date: '2016-09-05' +author: Shai Almog +--- + +![Header Image](/blog/3-image-tools-for-app-marketing/image-tools-for-app-marketing.jpg) + +Every now and again developers ask us how we do the graphics for our posts/promotions and up until recently the +answer was “photoshop”. While knowing photoshop is still very worthwhile we still like these 3 tools that provide great +shortcuts to creating both screenshots and art. + +### The App Launchpad + +[App Launchpad](http://theapplaunchpad.com/) is a newcomer to the scene, it’s still a new tool at the MVP stage. +The potential is still great and it generates reasonably attractive graphics such as these: + +[![App launchpad images contain a device frame with text/colors](/blog/3-image-tools-for-app-marketing/app-launchpad.png)](/img/blog/app-launchpad.png) + +Figure 1. App launchpad images contain a device frame with text/colors + +The UX for the tool is reasonably intuitive and you can work on several screenshots at once. There are some missing +basic features that I’d like to see moving forward but the tool is already pretty useful. E.g. we used it for the kitchensink +screenshots on [Android](https://play.google.com/store/apps/details?id=com.codename1.demos.kitchen) and +[iOS](https://itunes.apple.com/us/app/kitchen-sink-codename-one/id635048865). + +Hopefully they will improve the tool by adding: + + * Landscape support + + * Tablet skins + + * Thin fonts + + * More customization abilities e.g. image/texture backgrounds + +### Smart Mockups + +[Smart Mockups](http://smartmockups.com/) is a [PlaceIt](http://placeit.breezi.com/) clone that isn’t +as aggressively monetized. It allows you to take a screenshot and place it within a context of a device held by a user. +Normally this is slightly challenging to do in photoshop unless you have a ready made template. + +The image at the top of this post was generated with [Smart Mockups](http://smartmockups.com/) and Adobe Spark…​ + +### Adobe Spark + +[Spark](https://spark.adobe.com/) is a tool that makes typography easy. It does quite a few things to generate images +such as the image above that mix image filters, typography, shape decoration etc. + +All of those allow you to create meme style images as well as a wide variety of banners/promo images that you +can use to market your apps in the stores. + +[![Adobe Spark & Smart Mockups were used to create this image](/blog/3-image-tools-for-app-marketing/image-tools-for-app-marketing.jpg)](/img/blog/image-tools-for-app-marketing.jpg) + +Figure 2. Adobe Spark & Smart Mockups were used to create this image + +### Good Looking Graphics + +The app icon and screenshots are where the initial opinion of your app is formed. If the promotional material isn’t +good some users will still give your app the benefit of the doubt, but they will do so with a negative first impression. + +Good promotional material is no substitute for good app design, but it’s a step that you need to take. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chris Moore** — May 30, 2019 at 7:49 am ([permalink](https://www.codenameone.com/blog/3-image-tools-for-app-marketing.html#comment-24041)) + +> Hey Shai! +> +> Nice tips. I wonder whether you’ve tried Promomatic ([https://www.promomatic.com/)]()) for building app screenshots instead of AppLaunchPad? Super easy to use and cost effective when building for the app store launch. Found them on Product Hunt a few months back. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2F3-image-tools-for-app-marketing.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/5-cool-new-features-in-codename-one-for-netbeans-ide.md b/docs/website/content/blog/5-cool-new-features-in-codename-one-for-netbeans-ide.md new file mode 100644 index 0000000000..ee18860520 --- /dev/null +++ b/docs/website/content/blog/5-cool-new-features-in-codename-one-for-netbeans-ide.md @@ -0,0 +1,39 @@ +--- +title: 5 Cool New Features in Codename One for NetBeans IDE +slug: 5-cool-new-features-in-codename-one-for-netbeans-ide +url: /blog/5-cool-new-features-in-codename-one-for-netbeans-ide/ +original_url: https://www.codenameone.com/blog/5-cool-new-features-in-codename-one-for-netbeans-ide.html +aliases: +- /blog/5-cool-new-features-in-codename-one-for-netbeans-ide.html +date: '2014-01-19' +author: Shai Almog +--- + +![Header Image](/blog/5-cool-new-features-in-codename-one-for-netbeans-ide/5-cool-new-features-in-codename-one-for-netbeans-ide-1.png) + + + + + +![Picture](/blog/5-cool-new-features-in-codename-one-for-netbeans-ide/5-cool-new-features-in-codename-one-for-netbeans-ide-1.png) + + + + +An article of mine with the above title just +[ +got published in dzone +](http://netbeans.dzone.com/articles/5-cool-new-features-codename) +check it out and let us know what you think in the comments over there. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/5-tips-for-gamifying-your-mobile-app.md b/docs/website/content/blog/5-tips-for-gamifying-your-mobile-app.md new file mode 100644 index 0000000000..54e367c3db --- /dev/null +++ b/docs/website/content/blog/5-tips-for-gamifying-your-mobile-app.md @@ -0,0 +1,130 @@ +--- +title: 5 Tips for Gamifying Your Mobile App +slug: 5-tips-for-gamifying-your-mobile-app +url: /blog/5-tips-for-gamifying-your-mobile-app/ +original_url: https://www.codenameone.com/blog/5-tips-for-gamifying-your-mobile-app.html +aliases: +- /blog/5-tips-for-gamifying-your-mobile-app.html +date: '2013-03-23' +author: Shai Almog +--- + +![Header Image](/blog/5-tips-for-gamifying-your-mobile-app/5-tips-for-gamifying-your-mobile-app-1.png) + +This is a guest post by Yaniv Nizan who is the CEO and Co-Founder of +[ +The SOOMLA Project +](http://soom.la/) +, the platform for Creating In-App Purchase Stores for Mobile Games. Yaniv also writes in 4 different blogs including +[ +blog.soom.la +](http://blog.soom.la/) +, speaks in different industry events about gamification and game design and tweets +[ +@y_nizan +](http://twitter.com/y_nizan) +. + +* * * + +> Gamification is the practice of using game mechanics in a different context with a goal to engage users +> + +Mobile apps are in fierce competition these days. There are over one million apps available in the different marketplaces and while a user may install a large number of apps on his device. Recent research by Flurry shows that users don’t use many apps for very long and in fact only 25% of the apps survive after 3 months. + +[ +![Picture](/blog/5-tips-for-gamifying-your-mobile-app/5-tips-for-gamifying-your-mobile-app-1.png) +](/img/blog/old_posts/5-tips-for-gamifying-your-mobile-app-large-3.png) + +This is one of the main reasons why app developers need to invest a lot of resources in engaging the users and increasing the average length of activity for the users. One interesting way of doing that is through the user of gamification. Games are very popular in smartphones and most users are already accustomed to playing games on their mobile devices so the fit seems very natural here. + +Digging a bit deeper into gamification, there are a few basic game mechanics that are suited for gamifying most mobile apps: Goals or Achievements, Problem Solving and Awards. I’m deliberately leaving social out since it is not a purely game related. It is present in some games and in some apps. On top of the game mechanics gamification is also about making elements more responsive and providing instant gratification. These are easier to do on touch devices but not all apps are utilizing the power of this approach. + +So now that we know what Gamification is, let’s define the goal in the context of a mobile app. The idea here is to get the user in the engagement loop. The engagement loop is achieved when the user invests time in order to improve his value from the application and then he is willing to invest more time which will increase the value and so forth. The more iterations of this loop, the better the +[ +app engagement +](http://soom.la) +will be. + +[ +![Picture](/blog/5-tips-for-gamifying-your-mobile-app/5-tips-for-gamifying-your-mobile-app-2.png) +](/img/blog/old_posts/5-tips-for-gamifying-your-mobile-app-large-4.png) + +Here is how we can combine all of these together: + + + +## Tip 1 – Creating Engagement Opportunities for the User + +This is a key component in creating the engagement loop. You app needs to have elements that allow users to invest time and get more out of the app. One easy example for this is profile building. In apps that provide social interaction, investing time in your profile is not a required step but the more a user invests time in it, the better his experience will be. Same goes for apps that allow you to import your friends from other social networks. The more time you invest, the more engaging the app is likely to be for you. + +## Tip 2 – Encouraging Your Users to Invest the Time through Achievements + +While the user does get value from investing his time, he doesn’t get it right away. This is part of the reason why it’s important to provide a more instant gratification even for an action that is good for the user. NOTE – it’s important not to provide short term rewards for actions that will end up hurting the user – this can backfire and produce a negative result. Easy elements that can be added to encourage users are progress bar for completing his user profile or awards for connecting and inviting friends. + +## Tip 3 – Guide Users about the Value They Can Receive + +Once your app users invested time and unlocked more value. You can add responsive UX that guides them about opportunities to get more value as they appear. This could be anything from friend recommendations to relaying on the app for day to day tasks. If we take one example, a task management app can encourage users to connect the app with the calendar app through achievements and awards. Once the calendar app is connected, the task management app can recommend the user to add tasks after a meeting. + +## Tip 4 – Getting Rid of Clutter via Smart Unlocking + +While great apps allow users to get tremendous value, they also need to be very simple. The conflict here is that the more functionality you add to the app the more it is becoming more complicated. Luckily, gamification does provide a solution. Provided that you are already maintaining some score about the user, you can gradually unlock features based on his score or level. This approach allows you to keep the first experience simple and gradually add more value later on. + +## Tip 5 – Reward your Key Users + +Every successful app has users that evangelize the app and explain others how to get value from it. While you can design a great UX with guidance and tutorials, nothing beats a friend explaining the user how to use the app and showing him the end result. This is not about getting buzz by soliciting likes on Facebook. This is about finding the few that are really excited about the app and gamifying their evangelism activity. You could have awards such as the Educator, the Trainer and you could reward users for repeatedly mentioning your app. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — March 24, 2013 at 2:56 pm ([permalink](https://www.codenameone.com/blog/5-tips-for-gamifying-your-mobile-app.html#comment-24251)) + +> Anonymous says: +> +> Great post guys! +> +> Keep up the good work! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2F5-tips-for-gamifying-your-mobile-app.html) + + +### **Anonymous** — March 24, 2013 at 4:20 pm ([permalink](https://www.codenameone.com/blog/5-tips-for-gamifying-your-mobile-app.html#comment-21425)) + +> Anonymous says: +> +> Very cool. Thanks for the post! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2F5-tips-for-gamifying-your-mobile-app.html) + + +### **Anonymous** — November 13, 2013 at 10:25 am ([permalink](https://www.codenameone.com/blog/5-tips-for-gamifying-your-mobile-app.html#comment-21681)) + +> Anonymous says: +> +> Thanks for this post. Do you have any examples of utility apps that do this well? Eg, Telecoms, banking, power etc +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2F5-tips-for-gamifying-your-mobile-app.html) + + +### **Balbir singh** — February 7, 2018 at 10:16 am ([permalink](https://www.codenameone.com/blog/5-tips-for-gamifying-your-mobile-app.html#comment-23869)) + +> Balbir singh says: +> +> thanks for sharing this informative post about mobile app. +> [http://www.nanoarchsoftware…]() +> . +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2F5-tips-for-gamifying-your-mobile-app.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/64-bit-oss-vm.md b/docs/website/content/blog/64-bit-oss-vm.md new file mode 100644 index 0000000000..d5fb36df84 --- /dev/null +++ b/docs/website/content/blog/64-bit-oss-vm.md @@ -0,0 +1,82 @@ +--- +title: 64 bit & OSS VM +slug: 64-bit-oss-vm +url: /blog/64-bit-oss-vm/ +original_url: https://www.codenameone.com/blog/64-bit-oss-vm.html +aliases: +- /blog/64-bit-oss-vm.html +date: '2014-10-19' +author: Shai Almog +--- + +![Header Image](/blog/64-bit-oss-vm/64-bit-oss-vm-1.png) + + + + + +![64bit](/blog/64-bit-oss-vm/64-bit-oss-vm-1.png) + + + + + +Apple Just announced they will mandate 64 bit for all new submissions starting February 2015, luckily we are very prepared for that and we already support 64 bit builds in our new VM. + +This is a huge triumph for the architecture of our new VM which is very resilient to changes Apple might make in the future thanks to its pure C architecture. Our old XMLVM based approach is limited in that regard since it relies on the Boehm garbage collector which in turn relies on low level assembler and memory layouts heavily. Our new VM is both faster and more portable; now its also open source! + +In fact, the only portion that posed a slight challenge was porting the native libzbar which we use for QR/barcode reading. Everything related to the VM itself ported easily and works with the new high resolution devices as well as arm64. + +If you want to try your app with the new VM just submit a build with the build argument ios.newVM=true. We are now actively seeking bug reports, crashes and compilation errors with the new VM in order to be able to transition it into the default VM by January. If you get an error please reproduce it as a standalone project we can compile and attach it to an issue in the issue tracker describing the problem. + +We just committed the current beta of the new VM into SVN, its still not production grade but its now open source under the GPL + Class Path Exception. You can see the source under the VM directory of our SVN tree where you should see two projects. One is the bytecode translator and the other is the Java API implementation. + +Basically the architecture is very simple, it statically parses the bytecode using ASM and generates C source/header files that pretty much represent the bytecode as it is in Java. It has a rudimentary optimizer but nothing too shabby. + +The main focus in the future would be removing some of the stack operations in the bytecode by possibly converting the bytecode on the fly to something that would be more efficient on the device. We will probably stay with the stack based approach rather than go completely register based like DEX has for two major reasons: + +1\. Similarity to the source bytecode which makes it relatively simple to locate the relevant section. + +2\. The stack based approach is very powerful when combined with our GC so we will need it for the GC to work correctly. + +On a slightly unrelated note, IAP version 3.0 is now up on the build servers. We made a few corrections to the post from last week containing a discussion of the changes needed so if you use it please +[ +check out the revised post +](http://www.codenameone.com/blog/migrating-to-androids-in-app-purchase-30) +. + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — November 10, 2014 at 8:13 am ([permalink](https://www.codenameone.com/blog/64-bit-oss-vm.html#comment-21907)) + +> Anonymous says: +> +> I got an error when I tried to build with the new vm +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2F64-bit-oss-vm.html) + + +### **Anonymous** — November 26, 2014 at 8:14 am ([permalink](https://www.codenameone.com/blog/64-bit-oss-vm.html#comment-22175)) + +> Anonymous says: +> +> Can you post on the forum with more details e.g. build error log? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2F64-bit-oss-vm.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/8-to-6.md b/docs/website/content/blog/8-to-6.md new file mode 100644 index 0000000000..9a1b41d648 --- /dev/null +++ b/docs/website/content/blog/8-to-6.md @@ -0,0 +1,98 @@ +--- +title: 8 to 6+ +slug: 8-to-6 +url: /blog/8-to-6/ +original_url: https://www.codenameone.com/blog/8-to-6.html +aliases: +- /blog/8-to-6.html +date: '2014-09-14' +author: Shai Almog +--- + +![Header Image](/blog/8-to-6/8-to-6-1.png) + + + + +[ +![Picture](/blog/8-to-6/8-to-6-1.png) +](/img/blog/old_posts/8-to-6-large-2.png) + + + +iOS 8 and iPhone 6/6+ are nearly upon us and Codename One is ready for both! + + + + +We’ve just added device skins for iOS 6 and 6+, notice that due to the very high resolution you might want to disable scrolling. Notice that those skins are ridiculously large and as such might trigger an out of memory error when you try to run. To fix this just go to the project properties and select the run section. In it select the VM options and configure -Xmx128m or even higher. + + + + + + +The 6+ device will use the HD level DPI so you should make sure to have graphics at that resolutions in order to truly make use of that device. + + +The build servers will now take +[ +10 screenshots instead of 7 +](http://www.codenameone.com/3/post/2014/03/the-7-screenshots-of-ios.html) +for iOS devices, these include the 6 the 6+ and the landscape version of 6+. + + + + +The file names are: + + +[[email protected]](/cdn-cgi/l/email-protection) – 750 x 1334 + + + +[[email protected]](/cdn-cgi/l/email-protection) + +– 1242 x 2208 + + +[[email protected]](/cdn-cgi/l/email-protection) – 2208 x 1242 + + + + +You will notice that on stage Apple claimed that the device is 1080p which is true, but graphics for it is raised by a multiple of 3 then downscaled by hardware to simplify the programming model. + + + + +We are also running the latest gold master version of iOS 8 which seems to support Codename One applications just as well as iOS 7 without any changes required. + + + + +We’ll write more about the JavaZone conference trip soon. + + + + + + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/_index.md b/docs/website/content/blog/_index.md new file mode 100644 index 0000000000..7319f57e7c --- /dev/null +++ b/docs/website/content/blog/_index.md @@ -0,0 +1,11 @@ +--- +title: "Blog" +description: "Insights, release updates, tutorials, and engineering notes from the Codename One team." +ShowToc: false +outputs: + - HTML + - RSS + - Feed +--- + +Latest posts from Codename One. diff --git a/docs/website/content/blog/a-junior-software-developers-journey-at-codename-one.md b/docs/website/content/blog/a-junior-software-developers-journey-at-codename-one.md new file mode 100644 index 0000000000..1b5a73661f --- /dev/null +++ b/docs/website/content/blog/a-junior-software-developers-journey-at-codename-one.md @@ -0,0 +1,96 @@ +--- +title: A Junior Software Developer’s Journey at Codename One +slug: a-junior-software-developers-journey-at-codename-one +url: /blog/a-junior-software-developers-journey-at-codename-one/ +original_url: https://www.codenameone.com/blog/a-junior-software-developers-journey-at-codename-one.html +aliases: +- /blog/a-junior-software-developers-journey-at-codename-one.html +date: '2020-12-07' +author: Sergey Gerashenko +--- + +Hello Codename One community, my name is Sergey Gerashenko. I’m a junior software developer at Codename One. My journey here began 3 months ago when I passed my first interview at Codename One and my first task was to learn Java within 2 weeks. + +### Learning Java + +I knew a few programming languages like Python, C and C++ but was unfamiliar with Java or managed languages beforehand. + +Learning a completely new language in just two weeks seemed like an impossible task at first because it took me around five months to learn C++. + +I joined this [Java course](https://www.udemy.com/course/java-the-complete-java-developer-course) on Udemy and started learning immediately. + +My first impression of Java was great. It reminded me of C++ but much easier to understand and work with. After two weeks I felt confident with Java and started my work at Codename One. + +My first task was to update the Kitchen Sink cross-platform demo application to demonstrate all the main usages of Codename One framework. + +### The First Week + +My first week at the new job was a mess. The problem was that I came from the Real Time and Embedded background. I had never used Codename One or any other UI tools before and had a knowledge gap. + +I tried learning by watching tutorial videos on [Codename One Academy](https://codenameone.teachable.com/) but it was a bit difficult for someone without UI development experience. + +In the beginning, I didn’t understand some common terms and jargons and I had to Google my way around in order to get a good grasp of things. At the end of the first week, I was asked to show my progress. + +I barely wrote 100 lines of code (not the best ones). Even worst than that, I felt like I didn’t learn enough in the past week. In the second week, I decided to start from scratch. Now that I knew the basics, things became much easier. + +### What Really Helped? + +I found the [Codename One developer guide](https://www.codenameone.com/developer-guide.html) to be the best learning resource. It’s great for learning your way around the tool and understanding its components. + +In the [How Do I](https://www.codenameone.com/how-do-i.html) section I found some very helpful video tutorials that also helped a lot with learning common use cases, like the [Layout basics](https://www.codenameone.com/how_di_i/how-do-i-positioning-components-using-layout-managers.html) video, and the [How to convert a PSD Design into a Native Mobile App](https://www.codenameone.com/video/how-to-convert-a-psd-design-into-a-native-mobile-app.html). + +At that point, I was comfortable enough with a good foundation level knowledge and my work seemed much smoother and stress-free. + +### Learning Kotlin + +I started to enjoy the process of building apps, and everything else in between. When my app was ready, I was asked to write the [Kitchen Sink in Kotlin](https://github.com/codenameone/KitchenSinkKotlin) to demonstrate our Kotlin support. + +My first impression of Kotlin wasn’t that great just as my first impression of Java. Kotlin syntax was a little bit different from those languages that I knew so far, but when I studied it more I started to see its real beauty. + +Kotlin reminds me of Java but it seems more concise and readable after you get used to it. I spent the next two weeks on learning and writing the same Kitchen Sink app in Kotlin. + +The process wasn’t too hard as Kotlin has great tools to convert Java code to Kotlin. Though it was far from perfect and I spent a lot of time to review the code and make the necessary changes. + +After two months of hard work, learning and just enjoying the process, my app was ready for deployment and I was ready for my next challenge. + +### Kitchen Sink + +The Codename One [Kitchen Sink](https://play.google.com/store/apps/details?id=com.codename1.demos.kitchen) app is a great tool for those who want to start developing applications with Codename One tools. + +It explains all the basic components of Codename One and demonstrates the most common uses of them. It also demonstrates more complicated uses of Codename One like the low-level graphics possibilities with a gorgeous Clock demo and the use of GoogleMaps lib. + +And even better, the app contains links to the [source code](https://github.com/codenameone/KitchenSink) of the project, so anyone can just download the code, see how they can use specific components, play with them and experiment. + +But more importantly, users can see and learn about the application structure and how it needs to be written. + +![](https://www.codenameone.com/wp-content/uploads/2020/12/kitchen-sink-screenshot_1-169x300.png) + +![](https://www.codenameone.com/wp-content/uploads/2020/12/kitchen-sink-screenshot_2-169x300.png) + +![](https://www.codenameone.com/wp-content/uploads/2020/12/kitchen-sink-screenshot_3-169x300.png) + +![](https://www.codenameone.com/wp-content/uploads/2020/12/kitchen-sink-screenshot_4-169x300.png) + +![](https://www.codenameone.com/wp-content/uploads/2020/12/kitchen-sink-screenshot_5-169x300.png) +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **[email protected]** — December 26, 2020 at 2:56 pm ([permalink](https://www.codenameone.com/blog/a-junior-software-developers-journey-at-codename-one.html#comment-24368)) + +> [[email protected]](/cdn-cgi/l/email-protection) says: +> +> Looking forward to having an extra hand on CN1, Sergey. Welcome 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-junior-software-developers-journey-at-codename-one.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/a-new-idea.md b/docs/website/content/blog/a-new-idea.md new file mode 100644 index 0000000000..f502596e98 --- /dev/null +++ b/docs/website/content/blog/a-new-idea.md @@ -0,0 +1,285 @@ +--- +title: A New Idea +slug: a-new-idea +url: /blog/a-new-idea/ +original_url: https://www.codenameone.com/blog/a-new-idea.html +aliases: +- /blog/a-new-idea.html +date: '2016-04-05' +author: Shai Almog +--- + +![Header Image](/blog/a-new-idea/a-new-idea.png) + +Our current IntelliJ/IDEA plugin is seriously behind the times. In our recent survey it was very easy to spot +IDEA developers who were significantly less satisfied with Codename One than the rest of the developer community. +The IDEA plugin doesn’t include basic capabilities such as: + + * Java 8 Support + + * The New GUI builder + + * New Default application look/themes/icon + + * Builtin demo apps + + * The Generate Native Access functionality + + * The certificate wizard and a lot of the UI within the preferences + +### A New Direction + +The old plugin was developed by an excellent hacker who did a great job, but even the best code rots when +it is unmaintained. Worse, Jetbrains made some big changes between version 12 and now. The old plugin couldn’t +be compiled on the newer versions and exhibits odd bugs when running on newer versions of IDEA. + +We decided to rewrite the plugin from the ground up and discard a lot of the legacy both in terms of the plugin +and in terms of Codename One functionality. + +The main goal of this rewrite is reduction in code so we can have a very lean plugin with as much shared code +as possible. For that purpose the templates and builtin files are literally taken from the NetBeans plugin to facilitate +as much reuse as possible and allow for one release cycle to encapsulate everything. + +#### Java 8+ IntelliJ/IDEA 16+ + +The new plugin will only work on Java 8 or newer VM’s and will implicitly create Java 8 projects. + +Supporting legacy project structures doesn’t make sense for the new plugin although you could manually set that +in the generated project, this is probably unnecessary. + +#### New Preferences + +This might be the most controversial decision we’ve made with this plugin. Instead of using the native IDE +menu we chose to use the right click menu for a lot of features including our own preferences UI: + +![The preferences as well as other options are in the right click menu instead of the native IDE menu](/blog/a-new-idea/a-new-idea-menu.png) + +Figure 1. The preferences as well as other options are in the right click menu instead of the native IDE menu + +This launches a custom preferences UI written using Codename One that looks like this: + +![Preferences UI written in Codename One](/blog/a-new-idea/a-new-idea-preferences.png) + +Figure 2. Preferences UI written in Codename One + +![Preferences UI under the basics section](/blog/a-new-idea/a-new-idea-preferences-details.png) + +Figure 3. Preferences UI under the basics section + +The value of writing the preferences UI using the Codename One API is that it makes the maintenance of this +code far easier when compared to IDE specific code. A lot of features aren’t mapped to UI within the plugins +at this time because it’s just too much of a hassle to do this 3x times for every OS/platform. Right now we +have an internal debate on whether this should be the approach we take for all platforms, in the long run I think +this would be superior to using the IDE native preferences UI. + +The new preferences also allow us to integrate deeply with capabilities such as the iOS certificate wizard +which has the best most fluent integration in IntelliJ/IDEA. Personally I think it looks modern and better than the +IDE integrated approach. + +#### The New GUI Builder + +Support for the new GUI builder is builtin, as the builder is still in beta I’ll leave this as a somewhat “undocumented feature” +until we finish that work. I would like to mention though that the integration injects code directly to the AST and +dynamically updates it when the gui XML file is saved. + +Normally the GUI builder updates the sources via the ant task but we could find no way to do this in IntelliJ that +didn’t break basic things. + +### Video + +I’ve made a quick walkthru video of the new plugin, check it out: + +### Migration & Availability + +While we belive this should be maintained across versions we can’t be 100% sure about this. As with all rewrites +regressions probably exist. We will release the new plugin this Friday as part of our standard Friday release cycle. + +If you run into regressions we suggest creating a new project with the new plugin and migrating your code/settings +by copying them to the new plugin. Be sure to let us know immediately if you run into such issues. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Therk** — April 13, 2016 at 11:42 pm ([permalink](https://www.codenameone.com/blog/a-new-idea.html#comment-22656)) + +> Thank you for improving the plugin. It is more intuitive even though it may not be consistent with other IntelliJ plugins. Unfortunately, I started to get a NullPointerException when setting up the Run configuration for a new sample application. +> I am not sure the best way to report such issues, but the stack trace is: +> +> java.lang.NullPointerException +> +> at com.codename1.plugin.intellij.run.CodenameOneRunConfigurationEditor.initComponent([CodenameOneRunConfiguration…]():31) +> +> at com.codename1.plugin.intellij.run.CodenameOneRunConfigurationEditor.([CodenameOneRunConfiguration…]():27) +> at com.codename1.plugin.intellij.run.CodenameOneRunConfiguration.getConfigurationEditor([CodenameOneRunConfiguration…]():225) +> at com.intellij.execution.impl.ConfigurationSettingsEditor.([ConfigurationSettingsEditor…]():220) +> at com.intellij.execution.impl.ConfigurationSettingsEditorWrapper.([ConfigurationSettingsEditor…]():67) +> at com.intellij.execution.impl.SingleConfigurationConfigurable.([SingleConfigurationConfigur…]():65) +> at com.intellij.execution.impl.SingleConfigurationConfigurable.editSettings([SingleConfigurationConfigur…]():99) +> at com.intellij.execution.impl.RunConfigurable.a([RunConfigurable.java]():1090) +> at com.intellij.execution.impl.RunConfigurable.createNewConfiguration([RunConfigurable.java]():1123) +> at com.intellij.execution.impl.RunConfigurable$MyToolbarAddAction$2.consume([RunConfigurable.java]():1161) +> at com.intellij.execution.impl.RunConfigurable$MyToolbarAddAction$2.consume([RunConfigurable.java]():1158) +> at com.intellij.execution.impl.NewRunConfigurationPopup$1.onChosen([NewRunConfigurationPopup.java]():82) +> at com.intellij.execution.impl.NewRunConfigurationPopup$1.onChosen([NewRunConfigurationPopup.java]():48) +> at com.intellij.ui.popup.list.ListPopupImpl.a([ListPopupImpl.java]():386) +> at com.intellij.ui.popup.list.ListPopupImpl.handleSelect([ListPopupImpl.java]():346) +> at com.intellij.ui.popup.list.ListPopupImpl$MyMouseListener.mouseReleased([ListPopupImpl.java]():476) +> at java.awt.AWTEventMulticaster.mouseReleased([AWTEventMulticaster.java]():290) +> at java.awt.Component.processMouseEvent([Component.java]():6535) +> at javax.swing.JComponent.processMouseEvent([JComponent.java]():3324) +> at com.intellij.ui.popup.list.ListPopupImpl$MyList.processMouseEvent([ListPopupImpl.java]():542) +> at java.awt.Component.processEvent([Component.java]():6300) +> at java.awt.Container.processEvent([Container.java]():2236) +> at java.awt.Component.dispatchEventImpl([Component.java]():4891) +> at java.awt.Container.dispatchEventImpl([Container.java]():2294) +> at java.awt.Component.dispatchEvent([Component.java]():4713) +> at java.awt.LightweightDispatcher.retargetMouseEvent([Container.java]():4888) +> at java.awt.LightweightDispatcher.processMouseEvent([Container.java]():4525) +> at java.awt.LightweightDispatcher.dispatchEvent([Container.java]():4466) +> at java.awt.Container.dispatchEventImpl([Container.java]():2280) +> at java.awt.Window.dispatchEventImpl([Window.java]():2750) +> at java.awt.Component.dispatchEvent([Component.java]():4713) +> at java.awt.EventQueue.dispatchEventImpl([EventQueue.java]():758) +> at java.awt.EventQueue.access$500([EventQueue.java]():97) +> at java.awt.EventQueue$[3.run](:709) +> at java.awt.EventQueue$[3.run](:703) +> at java.security.AccessController.doPrivileged(Native Method) +> at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege([ProtectionDomain.java]():76) +> at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege([ProtectionDomain.java]():86) +> at java.awt.EventQueue$[4.run](:731) +> at java.awt.EventQueue$[4.run](:729) +> at java.security.AccessController.doPrivileged(Native Method) +> at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege([ProtectionDomain.java]():76) +> at java.awt.EventQueue.dispatchEvent([EventQueue.java]():728) +> at com.intellij.ide.IdeEventQueue.h([IdeEventQueue.java]():857) +> at com.intellij.ide.IdeEventQueue._dispatchEvent([IdeEventQueue.java]():654) +> at com.intellij.ide.IdeEventQueue.dispatchEvent([IdeEventQueue.java]():386) +> at java.awt.EventDispatchThread.pumpOneEventForFilters([EventDispatchThread.java]():201) +> at java.awt.EventDispatchThread.pumpEventsForFilter([EventDispatchThread.java]():116) +> at java.awt.EventDispatchThread.pumpEventsForFilter([EventDispatchThread.java]():109) +> at java.awt.WaitDispatchSupport$[2.run](:184) +> at java.awt.WaitDispatchSupport$[4.run](:229) +> at java.awt.WaitDispatchSupport$[4.run](:227) +> at java.security.AccessController.doPrivileged(Native Method) +> at java.awt.WaitDispatchSupport.enter([WaitDispatchSupport.java]():227) +> at [java.awt.Dialog.show](:1084) +> at com.intellij.openapi.ui.impl.DialogWrapperPeerImpl$[MyDialog.show](:792) +> at [com.intellij.openapi.ui.imp…](:465) +> at com.intellij.openapi.ui.DialogWrapper.invokeShow([DialogWrapper.java]():1661) +> at [com.intellij.openapi.ui.Dia…](:1610) +> at com.intellij.openapi.options.ex.SingleConfigurableEditor.access$001([SingleConfigurableEditor.java]():45) +> at com.intellij.openapi.options.ex.SingleConfigurableEditor$[1.run](:130) +> at com.intellij.openapi.project.DumbPermissionServiceImpl.allowStartingDumbModeInside([DumbPermissionServiceImpl.java]():31) +> at com.intellij.openapi.project.DumbService.allowStartingDumbModeInside([DumbService.java]():283) +> at [com.intellij.openapi.option…](:127) +> at com.intellij.execution.impl.EditConfigurationsDialog.access$001([EditConfigurationsDialog.java]():33) +> at com.intellij.execution.impl.EditConfigurationsDialog$[1.run](:57) +> at com.intellij.openapi.project.DumbPermissionServiceImpl.allowStartingDumbModeInside([DumbPermissionServiceImpl.java]():37) +> at com.intellij.openapi.project.DumbService.allowStartingDumbModeInside([DumbService.java]():283) +> at [com.intellij.execution.impl…](:54) +> at com.intellij.openapi.ui.DialogWrapper.showAndGet([DialogWrapper.java]():1625) +> at com.intellij.execution.actions.ChooseRunConfigurationPopup$8.perform([ChooseRunConfigurationPopup…]():974) +> at com.intellij.execution.actions.ChooseRunConfigurationPopup$ConfigurationListPopupStep$[2.run](…]():500) +> at java.awt.event.InvocationEvent.dispatch([InvocationEvent.java]():311) +> at java.awt.EventQueue.dispatchEventImpl([EventQueue.java]():756) +> at java.awt.EventQueue.access$500([EventQueue.java]():97) +> at java.awt.EventQueue$[3.run](:709) +> at java.awt.EventQueue$[3.run](:703) +> at java.security.AccessController.doPrivileged(Native Method) +> at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege([ProtectionDomain.java]():76) +> at java.awt.EventQueue.dispatchEvent([EventQueue.java]():726) +> at com.intellij.ide.IdeEventQueue.h([IdeEventQueue.java]():857) +> at com.intellij.ide.IdeEventQueue._dispatchEvent([IdeEventQueue.java]():658) +> at com.intellij.ide.IdeEventQueue.dispatchEvent([IdeEventQueue.java]():386) +> at java.awt.EventDispatchThread.pumpOneEventForFilters([EventDispatchThread.java]():201) +> at java.awt.EventDispatchThread.pumpEventsForFilter([EventDispatchThread.java]():116) +> at java.awt.EventDispatchThread.pumpEventsForHierarchy([EventDispatchThread.java]():105) +> at java.awt.EventDispatchThread.pumpEvents([EventDispatchThread.java]():101) +> at java.awt.EventDispatchThread.pumpEvents([EventDispatchThread.java]():93) +> at [java.awt.EventDispatchThrea…](:82) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-idea.html) + + +### **Therk** — April 14, 2016 at 12:21 am ([permalink](https://www.codenameone.com/blog/a-new-idea.html#comment-22484)) + +> A few suggestion on improving the IDEA plugin: +> 1\. In the Codename One Preferences, tabbing between fields does not seem to work, requiring a mouse click into next fields. For example in the Login or iOS Certificate Wizard. +> 2\. It is unclear if user is logged in. It would be good to show login email under Login icon if login was successful. +> 3\. Adding certificate, revokes existing certificate. It prompts “Your iTunes account already has an iOS appstore certificate. Would you like to overwrite it?”. If I click ‘No’, then no certificate is used. It would also help to know that old certificate will be revoked in the message. +> 4\. The iOS Certificate Wizard, tried to create certificate for each device. +> 5\. In the device list of iOS Certificate Wizard, showing Identifier would be helpful. +> 6\. It should allow to select existing App ID and name for an application. +> 7\. Under Global Preferences and iOS Certificate Wizard, App ID and name should probably not be required, as I think Global Preferences are to be shared between other CodenameOne application. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-idea.html) + + +### **Shai Almog** — April 14, 2016 at 2:36 am ([permalink](https://www.codenameone.com/blog/a-new-idea.html#comment-22585)) + +> Thanks! +> Those are great issues/RFE’s. +> The right place to file them so they don’t get lost under our workload is the issue tracker at [http://github.com/codenameo…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-idea.html) + + +### **Shai Almog** — April 14, 2016 at 8:08 am ([permalink](https://www.codenameone.com/blog/a-new-idea.html#comment-22766)) + +> Shai Almog says: +> +> Looking a bit further on this: +> +> 4\. Are you sure about this? It just adds the device to the provisioning profile. +> 6\. It should have the existing app id from your app which must match the package name of your project. +> 7\. The global version of the wizard should allow you to customize the app id as it can be a * certificate but it can reside anywhere e.g. I can make a com.mycompany.* or just plain * as my default. This matters to the provisioning profile. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-idea.html) + + +### **Shai Almog** — April 14, 2016 at 8:14 am ([permalink](https://www.codenameone.com/blog/a-new-idea.html#comment-22774)) + +> Shai Almog says: +> +> How do you set the run configuration? +> I see the problem but I can’t reproduce it to make sure the fix is correct. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-idea.html) + + +### **Eric Coolman** — April 28, 2016 at 9:50 pm ([permalink](https://www.codenameone.com/blog/a-new-idea.html#comment-22466)) + +> Eric Coolman says: +> +> Great work, and thanks! 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-idea.html) + + +### **James van Kessel** — May 20, 2016 at 3:56 pm ([permalink](https://www.codenameone.com/blog/a-new-idea.html#comment-22606)) + +> James van Kessel says: +> +> Hi Shai, For someone with an existing project, are there any warnings or cautions you’d give someone still using an older CN1 plugin (i am still on 3.1) before clicking “update Plugin”? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-idea.html) + + +### **Shai Almog** — May 21, 2016 at 3:51 am ([permalink](https://www.codenameone.com/blog/a-new-idea.html#comment-22611)) + +> Shai Almog says: +> +> If you update to the latest it will be the new plugin and there is no warning. Notice that on the plugin page at IDEA you can always download the older versions of the plugin if you need it while we fix a potential issue you might run into. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-idea.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/a-new-pipeline-for-windows-phone.md b/docs/website/content/blog/a-new-pipeline-for-windows-phone.md new file mode 100644 index 0000000000..9744816bcf --- /dev/null +++ b/docs/website/content/blog/a-new-pipeline-for-windows-phone.md @@ -0,0 +1,306 @@ +--- +title: A New Pipeline For Windows Phone +slug: a-new-pipeline-for-windows-phone +url: /blog/a-new-pipeline-for-windows-phone/ +original_url: https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html +aliases: +- /blog/a-new-pipeline-for-windows-phone.html +date: '2014-02-02' +author: Shai Almog +--- + +![Header Image](/blog/a-new-pipeline-for-windows-phone/a-new-pipeline-for-windows-phone-1.png) + + + + + +![Picture](/blog/a-new-pipeline-for-windows-phone/a-new-pipeline-for-windows-phone-1.png) + + + + +The Windows Phone port is one of our most painful ports, the platforms is so fragmented, volatile and rigid its remarkably hard to extract a common porting layer that will satisfy our requirements. We’ve just updated our servers with the 3rd port we did for Windows Phone, its experimental so its off by default, to activate it just use win.newPipeline=true in your build arguments. + + + + +As you may recall our first port targeted Windows Phone 7.5 and used XNA which Microsoft killed with Windows Phone 8. + + +Our second port was + + + +silverlight based and tried to dynamically create a scene-graph structure to match the graphics we are drawing in code, this is a very “imaginative” approach and it worked for most cases but had a lot of issues worst of which was very bad graphics performance and paint artifacts that were very hard to fix. + +The third approach takes a very different direction, we effectively create a writeable bitmap object and draw onto a huge int array representing the screen. This means we draw everything. Our initial attempt at this tried to use silverlight for this but this performed very badly, so we ported Pisces to C# and use that to some degree to get basic graphics primitives and image blitting working on the platform. This isn’t the best approach in terms of performance but its better than what we have now and might be good enough for now. If this pans out we can always port some of the low level code to direct x using the basic API’s we already implemented. + + + + +Please try this new port and let us know both here and in the discussion forum how it affects your application. + + + + + + +This was quite a bit of work that took a lot of effort we have a pretty large pipeline of tasks ahead of us both in terms of bug fixes and pending features, so if a particular issue you filed wasn’t addressed please bare with us as we work thru the backlog. Its OK to remind us occasionally since things sometimes do fall thru the cracks. + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — February 4, 2014 at 8:25 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-21435)) + +> Anonymous says: +> +> Still some minor bugs but way better than the previous support. Keep up the good work ! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — April 28, 2014 at 10:27 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-21837)) + +> Anonymous says: +> +> So far my development under WP has been going well, and I’m making a game. Performance wise, it’s “playable”, maybe not the best but I am using a low-end device for debugging. +> +> Overall it’s a good port, but better performance through through directX would be nice! 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — April 28, 2014 at 12:28 pm ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-21718)) + +> Anonymous says: +> +> Unfortunately I don’t think we will be able to use DirectX. The problem is that when you use DirectX we can’t use text and we can’t use widgets (e.g. TextInput), it might be possible to achieve something like that but it seems rather difficult in comparison to other platforms. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — April 30, 2014 at 5:59 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-21725)) + +> Anonymous says: +> +> No worries, the latest build of the game runs smooth on low-end devices! Had to improve some GC logic etc for the game. +> +> It really does show how powerfull CodenameOne is, great job guys! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — July 24, 2014 at 4:28 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-22104)) + +> Anonymous says: +> +> Hi! +> +> Is the win.newPipeline=true now on by default? I tried to build with and without it and the build seamed to generate the same .xap file. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — July 24, 2014 at 2:13 pm ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-21677)) + +> Anonymous says: +> +> Hi, +> +> yes its the default. You can set it to false to disable it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — October 30, 2014 at 5:57 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-21679)) + +> Anonymous says: +> +> Hello, has further improvement/updates been made since? Also what are the current limitations to this port compared to Android/IOs? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — October 30, 2014 at 9:42 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-21950)) + +> Anonymous says: +> +> The port is far inferior and there was no progress to speak of. From talking to our enterprise/corporate subscribers it seems they only want Windows Phone as a checklist feature and prefer we invest our efforts on the iOS/Android fronts. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — October 30, 2014 at 11:18 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-22290)) + +> Anonymous says: +> +> Thanks for the feedback. I am seeing WP gaining momentum and with Windows Phone 10, it might gain more in the near future. Its a pity CN1’s direction is currently dictated by current paying customers since your initial ethos was to create a toolchain that enables developers to write code once that would run on most major platforms. I don’t blame you Shai, but it would be so nice to see good support for at least these three major platforms, which might attract more paying customers. Some colleagues of mine are advising me to invest development in web apps which are more portable for major platforms in the long run. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — October 30, 2014 at 9:56 pm ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-22301)) + +> Anonymous says: +> +> Our direction was always dictated by paying users as we repeatedly stated in the discussion forum. +> +> Windows phone isn’t growing anywhere and got 3 total rewrites so far because of Microsoft’s flakiness. +> +> Try getting a non-trivial webapp to work on the mobile version of internet explorer not to mention the browser changes made in the Android 4.x branch which have no workarounds available then talk about the “portability of the web” nonsense. Anyone who says web is portable didn’t actually use it professionally on a wide scale. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — October 31, 2014 at 6:03 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-21799)) + +> Anonymous says: +> +> Shai, when people look at a product offered, they usually look at the company’s first web page (at least that the case with me), which states very clearly your support for major platforms such as Android, IOs, BlackBerry and Windows Phone so forgive me for not looking at your discussion forums about how they are ‘really’ supported and at what level. It initially sounds to me you support everything quite well to some extent until I read this blog article of yours. +> +> Agreed, Windows Phone may not have gained much traction until now, but in the country where I live, I see more people using it than iPhones surprisingly, as it is the case in some parts of Europe. I don’t understand your comment about blaming Microsoft for your support hindrance, but it would be disingenuous to blame Microsoft if you are unable to make it work properly with your platform’s architecture. +> +> My friend has a company that writes web apps quite successfully for various clients, both big and small. So yes, it all depends on the nature of the app, but your comment is a little strong about people that still write web apps. +> +> Looking at your pricing package I would have loved to pay as a corporate or enterprise customer if you support Windows Phone quite well. Do you support BB10? I reckon your customers are using the Android port for running on that platform. Going back to the main discussion, even if I am a paying customer, I won’t have the guarantee you will support Windows Phone platform because the majority of your paying customers don’t want it as a main feature (until they decide to) and I cannot compete with the majority which is my main concern and its difficult for me to invest money into your services with this uncertainty. Thanks and all the best to you, Jan. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — October 31, 2014 at 8:47 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-21822)) + +> Anonymous says: +> +> If you were a corporate customer it would be financially viable for us to take the 3-6 man months of engineering effort required to rewrite the Windows Phone port. +> +> We do give corporate/enterprise customers the guarantee that their priority use cases will be properly supported. Obviously the effort required for Windows Phone is much bigger than most of the other tasks we face mostly due to inherent design choices made by MS. +> +> Just so I’m clear about the word majority, we have a few pro customers who want Windows Phone, but no Enterprise/Corporate users who are interested in it. +> +> We have a couple of pro users to whom BB10 is important but they are satisfied with the option of using the APK and we try to keep the chief functionality level there working with BB10. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — December 27, 2014 at 6:32 pm ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-22249)) + +> Anonymous says: +> +> Hi, +> +> is there any progress in developing Apps for Win 8.x Phones? +> +> What is about ‘packing’ a wep app core within codenameone? +> +> is there any help article available for signing the app? +> +> Thanks, Jan +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — December 28, 2014 at 4:44 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-22042)) + +> Anonymous says: +> +> Hi, +> +> there is no need/option to sign for Windows Phone. MS signs on its own and since Windows Phone doesn’t have an OTA install option (without the store) there is no real need. Currently none of our enterprise customers have made a formal request to justify the effort on Windows Phone. We support desktop development which should work well for the more popular Windows platforms such as the Surface Pro. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — February 14, 2015 at 8:32 pm ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-24177)) + +> Anonymous says: +> +> Hi Shai, +> +> i tried to build a very simple app and deploy it to my +> +> Lumia 630 phone by clicking on the *.XAP File uploaded +> +> on OneDrive. +> +> It says something like (in german): +> +> This enterprise app cannot be installed… +> +> Do i have to sign it with windows phone sdk? +> +> I understand your last answer in the way that +> +> this is not necessary / possible ? +> +> Thanks for an answer, +> +> Jan +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — February 15, 2015 at 5:21 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-22102)) + +> Anonymous says: +> +> Windows Phone is the only “modern” mobile OS that doesn’t support installing apps over the air (or by click) only via cable sync or thru the store beta test process. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — February 23, 2015 at 8:52 pm ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-24196)) + +> Anonymous says: +> +> Hi Shai, +> +> sorry, but no success: +> +> – I tried to install the app via SD card, +> +> – it does not appears in the App “Store” +> +> – clicking on it in WP 8 file manager doesn’t work +> +> – i try to build it actuallay again (24-02-2015) +> +> the message stays the same (… cannot be installed) +> +> Oliver +> +> P.S. +> +> The same code (simple list of buttons) runs even +> +> on my very old sony ericsson k800i as j2me app… +> +> any idea? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + + +### **Anonymous** — February 24, 2015 at 3:45 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline-for-windows-phone.html#comment-22168)) + +> Anonymous says: +> +> See [http://www.codenameone.com/…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline-for-windows-phone.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/a-new-pipeline.md b/docs/website/content/blog/a-new-pipeline.md new file mode 100644 index 0000000000..27e6832189 --- /dev/null +++ b/docs/website/content/blog/a-new-pipeline.md @@ -0,0 +1,122 @@ +--- +title: A New Pipeline +slug: a-new-pipeline +url: /blog/a-new-pipeline/ +original_url: https://www.codenameone.com/blog/a-new-pipeline.html +aliases: +- /blog/a-new-pipeline.html +date: '2014-01-26' +author: Shai Almog +--- + +![Header Image](/blog/a-new-pipeline/a-new-pipeline-1.png) + + + + + +![Picture](/blog/a-new-pipeline/a-new-pipeline-1.png) + + + + +One of our enterprise developers started complaining about the performance of our Android port, which forced us to take a closer look at our rendering pipeline on Android. It seems that Google’s hardware acceleration broke pretty much all the best practices of the Android 2.x era and what we had wasn’t taking full advantage of “project butter” the codename for Google’s new Android rendering layer. + + + + + + +This took a lot of effort to adapt and the effort is still ongoing but we wrote a brand new rendering layer for Android, at the moment you would need to switch it on explicitly and it will only work for Android 3.x or newer. When we will feel that its stable we will flip the default switch and make this the default for all future Android builds. + + + + + + +If you want to play with it just use the build argument android.asyncPaint=true + + + + + + +In this mode all paint graphics operations are added to a “task” pipeline and rendered asynchronously which allows better utilization of the device GPU for some use cases. Because of that this mode returns false from Display.areMutableImagesFast() this allows us to optimize rendering to avoid double buffering paradigms where possible (e.g. within the MapComponent). + + + + + + +One of the nice unintended side effects of this rendering mode is that color reproduction on the device is more accurate in subtle ways. The rasterization process on Android devices is slightly different especially on +[ +PenTile +](http://en.wikipedia.org/wiki/PenTile_matrix_family) +devices (very common on Android) and when we use this approach such devices produce a more accurate result. + + + + + + +Another unexpected bonus we got as a result of this change was that Android related GPU debugging tools started working for Codename One applications. Unfortunately, they indicated extreme overdraw issues for some cases. Overdraw indicates that we paint the same pixel multiple times to draw a single form which means the UI will effectively be slower. Androids tools are really good at pointing out a problem but they are awful at pointing us to the location of the problem. So we had to extend our performance monitor tool and add a special mode to it that shows the exact graphics operations performed by every component painting itself. This can be illuminating when trying to see why a specific UI is so slow, it also provides stack traces for every graphics operation. + + + + + + +To try it just open the performance monitor from the simulator and select the second tab then refresh within the form you want to inspect. You can then traverse the tree of components and see the exact rendering calls that were used to draw every single component within the hierarchy. + + + + + + +Using this tool we noticed that the parent form drew itself twice for every rendering cycle, it turns out that a special case needed only for transitions was active with every repaint. This was easy to fix in the core and should provide a small performance boost to Codename One applications on all platforms. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — January 28, 2014 at 5:22 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline.html#comment-21912)) + +> Anonymous says: +> +> Yes! Great Job! +> +> This is something I’ve really been waiting for. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline.html) + + +### **Anonymous** — February 5, 2014 at 5:46 am ([permalink](https://www.codenameone.com/blog/a-new-pipeline.html#comment-24236)) + +> Anonymous says: +> +> It’s funny because just yesterday I thought I noticed my app was running smoother, sometimes its easy to forget you eager beavers are improving our lives secretly and remotely, I appreciate this so much. As for ever draw, Im assuming you can detect if something wont be scene and not render it, a little like a 2d game tile engine. I THINK though that this new build hint is making the native browsers I have embedded in my app flash. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline.html) + + +### **Anonymous** — March 12, 2014 at 1:13 pm ([permalink](https://www.codenameone.com/blog/a-new-pipeline.html#comment-21796)) + +> Anonymous says: +> +> Excellent! I think the android port has been in need of a serious performance review for quite some time now. Android being the mobile platform with the most market share, it would be quite expedient if performance on this platform is focused on more intently. Looking forward to hearing more about this. Thanks! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fa-new-pipeline.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/a-thank-you-an-important-update-on-android-builds.md b/docs/website/content/blog/a-thank-you-an-important-update-on-android-builds.md new file mode 100644 index 0000000000..a4fea59ca9 --- /dev/null +++ b/docs/website/content/blog/a-thank-you-an-important-update-on-android-builds.md @@ -0,0 +1,94 @@ +--- +title: A Thank You & an Important Update On Android Builds +slug: a-thank-you-an-important-update-on-android-builds +url: /blog/a-thank-you-an-important-update-on-android-builds/ +original_url: https://www.codenameone.com/blog/a-thank-you-an-important-update-on-android-builds.html +aliases: +- /blog/a-thank-you-an-important-update-on-android-builds.html +date: '2016-02-02' +author: Shai Almog +--- + +![Header Image](/blog/a-thank-you-an-important-update-on-android-builds/html5-banner.jpg) + +We’d like to thank all of you who signed up to the pro subscription, the release of 3.3 is the perfect time to +do that. So we are opening up the JavaScript build target for 1 year until March 1st 2017 to all current pro subscribers! +If you have a pro subscription you can start sending a JavaScript build right away and experiment with porting +your app to the web… +If you don’t have a pro license currently then you have until March 15th to upgrade and enjoy this offer. After +March 15th the JavaScript port will return to enterprise only status for everyone who didn’t signup prior to that. + +If you are not familiar with the JavaScript port check out Steve’s [great writeup](/blog/javascript-port.html) +on it, you can also try out some of our demos live right now [here](/demos.html) +(using desktop or mobile browsers). Just click the JS Port link at the bottom right section of a demo e.g. +restaurant or property cross. +FYI If you cancel the subscription during this time or let it lapse this capability will be lost so make sure to keep it in place. + +#### Memory Issue on Android Builds + +With the switch to gradle in Android builds we experienced memory issues for some cases when building huge +apps. For some cases ading `android.gradle=false` to the build hints was enough but for others +not so much. + +The problem relates to the size of Google Play Services which are an essential part of Android applications but +have grown to a size that is pretty big. We need play services for better location tracking, in-app-purchase, push +notification, maps etc. +In the past we had the build hint `android.includeGPlayServices` which +tried to be smart about play services but its a bit too coarse as it only accepts true/false. + +To alleviate this issue we deprecated the `android.includeGPlayServices` and are introducing +the new build hints below that will allow you to selectively include a play service. This means that future builds +to the Codename One build servers can have one of the following 5 states: + + 1. `android.includeGPlayServices=true` & one or more of the `android.playService` +entries defined – this is an illegal state and will cause the build to fail + 2. `android.includeGPlayServices=true` & no `android.playService` +entries defined – this will fallback to compatibility mode + 3. `android.includeGPlayServices=false` & no `android.playService` +entries defined – play services won’t be included + 4. `android.includeGPlayServices` undefined & no `android.playService` +entries defined – some play services will be included by default specifically: plus, auth, base, analytics, gcm, location, maps, +ads. + 5. `android.includeGPlayServices` undefined & one or more `android.playService` +entries defined – only the play services you explicitly select will be included. + +The last two are a bit confusing so just to clarify if you do this: + + + android.playService.plus=true + +The only play service included will be plus. However, if you don’t define any build hints specifically the above list +of play services will be included. This is a “sensible default mode” that we picked to make the transition easier. + +The list of supported hints follows, they all accept true/false as arguments for inclusion/exclusion. + + + android.playService.plus + android.playService.auth + android.playService.base + android.playService.identity + android.playService.indexing + android.playService.appInvite + android.playService.analytics + android.playService.cast + android.playService.gcm + android.playService.drive + android.playService.fitness + android.playService.location + android.playService.maps + android.playService.ads + android.playService.vision + android.playService.nearby + android.playService.panorama + android.playService.games + android.playService.safetynet + android.playService.wallet + android.playService.wearable + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/accelerometer-code-freeze.md b/docs/website/content/blog/accelerometer-code-freeze.md new file mode 100644 index 0000000000..d026f3a95b --- /dev/null +++ b/docs/website/content/blog/accelerometer-code-freeze.md @@ -0,0 +1,43 @@ +--- +title: Accelerometer & Code Freeze +slug: accelerometer-code-freeze +url: /blog/accelerometer-code-freeze/ +original_url: https://www.codenameone.com/blog/accelerometer-code-freeze.html +aliases: +- /blog/accelerometer-code-freeze.html +date: '2015-04-12' +author: Shai Almog +--- + +![Header Image](/blog/accelerometer-code-freeze/sensors.jpg) + +Devices have sensors such as accelerometer, GPS and up until now our support for them was relatively basic. +Chen recently introduced a [cn1lib](https://github.com/chen-fishbein/sensors-codenameone) +that includes support for various types of sensors on the device. Its really simple to use: + + + SensorsManager sensor = SensorsManager.getSenorsManager(SensorsManager.TYPE_ACCELEROMETER); + if (sensor != null) { + sensor.registerListener(new SensorListener() { + public void onSensorChanged(long timeStamp, float x, float y, float z) { + //do your stuff here... + } + }); + } + +Check it out if you need access to such features. + +### Code Freeze + +We will be entering code freeze later today which should allow us to gear up towards the 3.0 release of Codename One +in two weeks. All commits will be made against an issue and always with a peer review. Releasing 3.0 will allow +us to improve versioned builds and cleanup our issue tracker. We already cleared more than 100 issues in the past +week in an effort to make this a high quality polished release. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/accordion-component.md b/docs/website/content/blog/accordion-component.md new file mode 100644 index 0000000000..2f66dd8d58 --- /dev/null +++ b/docs/website/content/blog/accordion-component.md @@ -0,0 +1,52 @@ +--- +title: Accordion Component +slug: accordion-component +url: /blog/accordion-component/ +original_url: https://www.codenameone.com/blog/accordion-component.html +aliases: +- /blog/accordion-component.html +date: '2016-06-18' +author: Chen Fishbein +--- + +![Header Image](/blog/accordion-component/accordion-post.png) + +The [Accordion](https://www.codenameone.com/javadoc/com/codename1/components/Accordion.html) ui pattern +is a vertically stacked list of items. Each item can be opened/closed to reveal more content similarly to a +[Tree](https://www.codenameone.com/javadoc/com/codename1/ui/tree/Tree.html) however unlike the +`Tree` the `Accordion` is designed to include containers or arbitrary components rather than model based data. + +This makes the `Accordion` more convenient as a tool for folding/collapsing UI elements known in advance +whereas a `Tree` makes more sense as a tool to map data e.g. filesystem structure, XML hierarchy etc. + +Note that the `Accordion` like many composite components in Codename One is scrollable by default which +means you should use it within a non-scrollable hierarchy. If you wish to add it into a scrollable `Container` you +should disable it’s default scrollability using `setScrollable(false)`. + + + Form f = new Form("Accordion", new BorderLayout()); + Accordion accr = new Accordion(); + accr.addContent("Item1", new SpanLabel("The quick brown fox jumps over the lazy dogn" + + "The quick brown fox jumps over the lazy dog")); + accr.addContent("Item2", new SpanLabel("The quick brown fox jumps over the lazy dogn" + + "The quick brown fox jumps over the lazy dogn " + + "The quick brown fox jumps over the lazy dogn " + + "The quick brown fox jumps over the lazy dogn " + + "")); + + accr.addContent("Item3", BoxLayout.encloseY(new Label("Label"), new TextField(), new Button("Button"), new CheckBox("CheckBox"))); + + f.add(BorderLayout.CENTER, accr); + f.show(); + +![Accordion component](/blog/accordion-component/components-accordion.png) + +Figure 1. Accordion component + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/accordion-control-xcode-migration-update.md b/docs/website/content/blog/accordion-control-xcode-migration-update.md new file mode 100644 index 0000000000..2044efa974 --- /dev/null +++ b/docs/website/content/blog/accordion-control-xcode-migration-update.md @@ -0,0 +1,55 @@ +--- +title: Accordion Control & Xcode Migration Update +slug: accordion-control-xcode-migration-update +url: /blog/accordion-control-xcode-migration-update/ +original_url: https://www.codenameone.com/blog/accordion-control-xcode-migration-update.html +aliases: +- /blog/accordion-control-xcode-migration-update.html +date: '2016-08-31' +author: Shai Almog +--- + +![Header Image](/blog/accordion-control-xcode-migration-update/accordion-post.png) + +In the coming update we have a new API to expand/collapse an `Accordion` component programmatically similar to the `Tree` component. + +To achieve this we introduced three new API’s to the `Accordion` class: + + + /** + * Returns the body component of the currently expanded accordion element or null if none is expanded + * @return a component + */ + public Component getCurrentlyExpanded(); + + /** + * Expands the accordion with the given "body" + * @param body the body component of the accordion to expand + */ + public void expand(Component body); + + /** + * Closes the accordion with the given "body" + * @param body the body component of the accordion to close + */ + public void collapse(Component body); + +All of these methods get/return the body of the accordion which is probably the best way to identify an accordion node. + +### Xcode Migration + +The migration to the new xcode servers is going well so far. We did experience some minor issues the biggest was the need to use `https` has kicked in as a result of the newer tooling. + +Pretty much everything seems to be in order and we migrated other servers to pick up the load so builds should be back to their typical build times. Before that builds might have been slower but once the migration is complete we’ll have more servers than we had when we started off making builds even faster. + +Right now we still have the `iphone_old` build target running, we plan to remove it by 3.6 (due December) so if you depend on it we suggest you keep us posted! + +Notice that once it’s removed we won’t be able to restore it as it depends on a legacy version of Mac OS X no longer sold. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/adding-google-play-ads.md b/docs/website/content/blog/adding-google-play-ads.md new file mode 100644 index 0000000000..a8e5437bd9 --- /dev/null +++ b/docs/website/content/blog/adding-google-play-ads.md @@ -0,0 +1,172 @@ +--- +title: Adding Google Play Ad's +slug: adding-google-play-ads +url: /blog/adding-google-play-ads/ +original_url: https://www.codenameone.com/blog/adding-google-play-ads.html +aliases: +- /blog/adding-google-play-ads.html +date: '2013-12-03' +author: Shai Almog +--- + +![Header Image](/blog/adding-google-play-ads/adding-google-play-ads-1.png) + + + + + +![Ad](/blog/adding-google-play-ads/adding-google-play-ads-1.png) + + + + +We are officially code frozen so only critical bug fixes should be resolved until the actual release. The very last feature to make it in is support for +[ +Google Play Ads +](https://developers.google.com/mobile-ads-sdk/) +on iOS/Android. We currently only work with the Admob SDK as we move along we might add additional options. + + +To enable mobile ads just +[ +create an ad unit +](https://apps.admob.com/?pli=1#monetize/adunit:create) +in Admob’s website, you should end up with the key similar to this: + +ca-app-pub-8610616152754010/3413603324 + + +To enable this for Android just define + +android.googleAdUnitId= + + +ca-app-pub-8610616152754010/3413603324 in the build arguments and for iOS use the same as in ios.googleAdUnitId. The rest is seamless, the right ad will be created for you at the bottom of the screen and the form should automatically shrink to fit the ad. This shrinking is implemented differently between iOS and Android due to some constraints but the result should be similar and this should work reasonably well with device rotation as well. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **juanpgarciac** — May 22, 2015 at 9:17 pm ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-22216)) + +> juanpgarciac says: +> +> There is a way to check the functionablity in the debug process ? cause I’d follow the steps and it doesn’t show anything… thanks for sharing +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + + +### **Shai Almog** — May 23, 2015 at 6:32 am ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-22112)) + +> Shai Almog says: +> +> Its supposed to be seamless. On which device are you running into a problem? +> Notice this will only work on devices and not the simulator. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + + +### **App Maker** — January 10, 2016 at 9:30 pm ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-22406)) + +> App Maker says: +> +> monetize option is not available! can u please tell me why? n how can i get it?! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + + +### **Shai Almog** — January 11, 2016 at 3:22 am ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-22498)) + +> Shai Almog says: +> +> We removed it as it was hard to maintain across IDE’s. We provided several newer monetization options including several ad based cn1libs [https://www.codenameone.com…]() +> +> And this option which doesn’t require the monetization section, just a build hint. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + + +### **Pugazhendi E** — March 26, 2016 at 7:36 am ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-22668)) + +> Pugazhendi E says: +> +> admob ads are not coming…I set the admob adunit ID in build arguments in netbeans ide…if i run a app, app ll work bt ads ll nt come…I followed the codename procedure… help me.. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + + +### **Shai Almog** — March 27, 2016 at 4:25 am ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-22459)) + +> Shai Almog says: +> +> Is this on the device? Which device type? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + + +### **Jean Carlos Rojas Ramirez** — June 8, 2016 at 11:35 pm ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-22833)) + +> Jean Carlos Rojas Ramirez says: +> +> I am working on an app and I can add the hint for Android but I would like to know which I should use for windows phone. Thanks, +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + + +### **Shai Almog** — June 9, 2016 at 5:05 am ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-21629)) + +> Shai Almog says: +> +> We don’t currently support Windows Phone with ads. AFAIK Googles AdMob isn’t available on Windows Phone. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + + +### **Jean Carlos Rojas Ramirez** — June 9, 2016 at 5:24 am ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-22826)) + +> Jean Carlos Rojas Ramirez says: +> +> Right now there is a version for windows phone for AdMob. If we build a windows phone app we can add the AdMob AdUnit for those builds. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + + +### **Shai Almog** — June 10, 2016 at 3:46 am ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-22612)) + +> Shai Almog says: +> +> OK. Either way Windows Phone is on the way out at Microsoft and I doubt Google would support that version. We are switching to the UWP port for universal Windows 10 support. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + + +### **Pugazhendi E** — July 25, 2016 at 1:27 pm ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-22843)) + +> Pugazhendi E says: +> +> yes sir..I ve tested this app with lenevo smartphone….app works well but ads ll not come +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + + +### **Shai Almog** — July 26, 2016 at 4:11 am ([permalink](https://www.codenameone.com/blog/adding-google-play-ads.html#comment-22928)) + +> Shai Almog says: +> +> That’s probably related to these changes [https://github.com/codename…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fadding-google-play-ads.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/admob-interstitial-ads-supertabs.md b/docs/website/content/blog/admob-interstitial-ads-supertabs.md new file mode 100644 index 0000000000..f2598ad857 --- /dev/null +++ b/docs/website/content/blog/admob-interstitial-ads-supertabs.md @@ -0,0 +1,56 @@ +--- +title: Admob Interstitial Ads & Supertabs +slug: admob-interstitial-ads-supertabs +url: /blog/admob-interstitial-ads-supertabs/ +original_url: https://www.codenameone.com/blog/admob-interstitial-ads-supertabs.html +aliases: +- /blog/admob-interstitial-ads-supertabs.html +date: '2014-10-26' +author: Shai Almog +--- + +![Header Image](/blog/admob-interstitial-ads-supertabs/admob-interstitial-ads-supertabs-1.png) + + + + + +![Picture](/blog/admob-interstitial-ads-supertabs/admob-interstitial-ads-supertabs-1.png) + + + + + + + + +Ram (the developer of +[ +yhomework +](http://www.codenameone.com/featured-yhomework.html) +), wanted to improve his ad revenue on Android/iOS thru interstitial (full screen) ads and integrated those using native interfaces. Kindly enough he contributed these changes back and Chen packaged this as a cn1lib which you can now easily use to add support for +[ +full screen ads to your Android/iOS apps +](https://code.google.com/p/admobfullscreen-codenameone/) +. + +On a different subject a long time RFE has been the ability to customize the tabs using a more powerful API. The main blocker for that has been the hardcoding of Buttons (or really radio buttons) as tabs in the Tabs component. + +With the upcoming version of Codename One you will be able to replace the usage of Button with just about anything by overriding a set of protected methods in the Tabs component. These effectively allow the Tabs class to understand the structure of your potentially complex class and communicate the requirements of the component. In the relatively simplistic implementation below I just used a layered layout to place a close button in the right side of every tab. This is code I used in the kitchen sink demo to test this effect. + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/aligning-prices.md b/docs/website/content/blog/aligning-prices.md new file mode 100644 index 0000000000..ee809af488 --- /dev/null +++ b/docs/website/content/blog/aligning-prices.md @@ -0,0 +1,258 @@ +--- +title: Aligning Prices +slug: aligning-prices +url: /blog/aligning-prices/ +original_url: https://www.codenameone.com/blog/aligning-prices.html +aliases: +- /blog/aligning-prices.html +date: '2015-05-10' +author: Shai Almog +--- + +![Header Image](/blog/aligning-prices/pricing-change.png) + +Our pricing has been inconsistent with the rest of the industry for quite some time specifically the price of the +basic subscription which is a losing tier. Based on Industry norms the basic subscription should be far more +expensive and doesn’t come close to covering the costs of running Codename One’s extensive cloud +infrastructure. So on June 1st we will raise the price of the basic subscription to 19USD which is still very +affordable. Notice that **if you are a current subscriber or sign up before June 1st you can keep paying +at the 9USD rate!** +However, if you let your subscription lapse we will not be able to recover it and you would need to switch to the 19USD +level… + +This is an important step for the health of the company as the costs of hosting our infrastructure are growing fast +and basic subscriptions just aren’t carrying the weight. + +As part of this move we also analyzed our build server usage and noticed many developers in the free tier who +place a very heavy toll on the build servers with long builds that eventually cost in service degradation to everyone. +That is one of the reasons we originally made the iOS build quota so limiting… + +So we are now reducing the credits for iOS builds to 8 credits per build (from 20) but also placing a size quotas on +builds from free users to reduce both our storage costs and build times (upload/download and server instance costs). +We are sure this step will improve performance for everyone involved and help people try Codename One before +committing to a paid account. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Maaike Z** — May 12, 2015 at 7:43 pm ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-21649)) + +> Maaike Z says: +> +> I understand the price change, but I’m not happy with it (I do this as a hobby). For a company this is ‘nothing’ of course. But why don’t you make offline building easier? Then you don’t need the expensive infrastructure (or at least users place less toll on the build servers). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Shai Almog** — May 13, 2015 at 4:27 am ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22250)) + +> Shai Almog says: +> +> That’s why we increased the free quota for iOS builds to make it easier on the hobbyist crowd to work without a subscription at all. +> Some people seem to think we have an ability to build offline, we send builds to the build servers just like everyone else… Offline building is technically impractical since the build process is so complex, fluid and has so many dependencies. +> And don’t get me started on manpower costs… Offering things for free doesn’t keep the lights on in any company. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Fabrício Cabeça** — May 13, 2015 at 7:39 pm ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22383)) + +> Fabrício Cabeça says: +> +> Hi Maaike, I think you may be understimating the offline building +> costs, and you should add to it your own time to keep your offline build +> server(s) up to date with all SDKs. I have a pro account and I have the +> knowledge and a minimal infrastructure that could be used to create +> offline build servers, but I prefer to focus in the development itself, that’s what codenameone is all about. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Maaike Z** — May 15, 2015 at 1:52 pm ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22110)) + +> Maaike Z says: +> +> @codenameone:disqus : I totally understand that you can’t offer everything for free. It’s impossible for a company to do everything for free. That doesn’t wipe away my wish to have a good product for less :). +> +> @fabriciocabeca:disqus I wish I could choose. I have time to make a build server and if everything is set up well once, I only have to keep everything up to date. Sometimes I prefer to have my own server to be not dependent of Codename One (that’s actually one of the drawbacks for me, the dependence of the company). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **J.C** — May 15, 2015 at 3:09 pm ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-24169)) + +> J.C says: +> +> So, just to clarify, if I pay 9USD before end of this month, how much will I pay at end of June? 19USD or still 9USD? Also, why don’t you also include an option for annual or 6 month subscriptions for Basic users to help us save cost for monthly transactions fees? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Shai Almog** — May 15, 2015 at 4:26 pm ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22138)) + +> Shai Almog says: +> +> Yes. +> We didn’t provide annual subscriptions because they won’t save much on the basic level (19 is still pretty low) you do have a point though, its something we should add. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **J.C** — May 15, 2015 at 5:49 pm ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-21650)) + +> J.C says: +> +> Sorry you didn’t answer my question, 19USD or 9USD? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Chen Fishbein** — May 16, 2015 at 6:07 am ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22251)) + +> Chen Fishbein says: +> +> if you are a current subscriber or sign up before June 1st you can keep paying at the 9USD +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Maaike Z** — May 21, 2015 at 9:15 pm ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22073)) + +> Maaike Z says: +> +> What about the 1mb quota for not subscribed users? Is it de jar sent to the server with a max quota of 1 mb or the final app or … ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Shai Almog** — May 22, 2015 at 3:44 am ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22411)) + +> Shai Almog says: +> +> That email was poorly worded IMO. It was sent without my review. +> The limit applies to the built JAR before sending otherwise it would be meaningless since the servers would have had to do all the work (and wasted the paid quotas we are spending) so there would have been no saving. +> To be clear we didn’t just pull out that number, we reviewed the sizes of free user builds coming in and concluded that well over 90% would fit under this limit right now or with very small modifications. The goal is to stop the outliers so we can provide essentially more quota (e.g. increased iOS build credits). Things like the kitchen sink demo which is really wasteful (several huge themes, a video etc.) will not fit, but its not a common app. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Eric** — May 22, 2015 at 9:31 am ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22111)) + +> Eric says: +> +> The resource file can only have the theme which can be bigger than 1Mb. This resource file is always added to the jar file before sending so the problem persist because a very simple app with a custom theme will not fit too because of the size of the theme file. How can you resolve that? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Shai Almog** — May 22, 2015 at 10:14 am ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-24170)) + +> Shai Almog says: +> +> You can dynamically download a theme on the device to workaround that but yest that is something that won’t work as well… +> Most themes should be optimizable see: [http://codenameone.com/blog…]() +> +> Unfortunately more elaborate themes won’t make it in. The main problem is that we can’t really tell how large your code is and how large the theme is (before doing all the work) and even if we could it would still cost us quite a bit more to build/host larger files. We tried to draw a line that makes sense for most and would allow us the leverage to increase build quotas which we felt were lacking. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **huwab0** — May 22, 2015 at 10:15 am ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22355)) + +> huwab0 says: +> +> This effectively kills my project. +> +> Our project is much larger than 1MB because we suppy a chinese font and several word and character lists. +> +> I rarely build on the server, so I wouldn’t mind if big jars cost more build credits!? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Eric** — May 22, 2015 at 10:32 am ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22296)) + +> Eric says: +> +> Shai, you must make a poll to users to know if they want more ios buid quotas or more app size. It’s not good to decide for users. If you cannot know the size of the code in the jar file so your first answer is not the right answer. You can not limit us if you cannot just track the size of our code without the resource file. This a serious problem that you create for developers +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Chen Fishbein** — May 22, 2015 at 10:56 am ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22139)) + +> Chen Fishbein says: +> +> Resource files when packaged to the jar are reduced by size, besides plenty of complex themes are in the 400-500k range uncompressed. +> This should be sufficient for a user to properly evaluate the product before he/she commits to a paid account. +> This is a crucial step for the health of the company we need the heavy users to start and help us pay the bills $9 or even $19 is pretty valuable for the product and service we provide. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Chen Fishbein** — May 22, 2015 at 10:58 am ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22363)) + +> Chen Fishbein says: +> +> I hope paying $9 or even $19 for our service shouldn’t be the mortal point to your project +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **huwab0** — May 22, 2015 at 1:00 pm ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-24179)) + +> huwab0 says: +> +> Actually, we try to make our project break even, but since there is hardly any money in our kind of applications, actually all costs need to be avoided. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **rhg1968** — May 22, 2015 at 1:04 pm ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22418)) + +> rhg1968 says: +> +> I for one totally support this change and understand why it is necessary. Codename one has been more than generous allowing you to build production applications for free for years. A company can’t go on this way forever and afford to stay in business and improve the system. I think it’s great that the free tier will still give people a lot so that they can truly evaluate the platform. I also think it’s more than generous to offer us the 9 price before raising the price. I have subscribed to the basic level now and look forward to developing with Codename one. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Benjamin Vander Stichelen** — May 23, 2015 at 2:35 am ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22338)) + +> Benjamin Vander Stichelen says: +> +> This will kill the project i’m working on, when creating the app every 2-3 updates creates a bug and time to investigate what went wrong. +> I understand that every company needs adjustments. Buth why don’t do it like google. +> The existing accounts don’t get changes the new accounts get limitations. +> +> When google decides to remove the project it’s removed buth meanwhile it’s on you got it like it was from the beginning for you. +> +> I’m surious to need to say that when they ask me would you do it again with codenameone the answer is no. +> +> That’s my opinion, now you are forcing us to do it from now on with the existing proyect. +> +> Greeting,s +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + + +### **Chen Fishbein** — May 23, 2015 at 5:37 am ([permalink](https://www.codenameone.com/blog/aligning-prices.html#comment-22209)) + +> Chen Fishbein says: +> +> I understand the frustration, but in order to keep on providing the product and service in high quality the heavy accounts needs to start and pay. +> I hope we do become google one day, but even google when they change their terms or cancel projects it will effect all their users. +> We might consider exceptions in special cases, feel free to reach out to me. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faligning-prices.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/alphabet-scroll.md b/docs/website/content/blog/alphabet-scroll.md new file mode 100644 index 0000000000..85ec7803d3 --- /dev/null +++ b/docs/website/content/blog/alphabet-scroll.md @@ -0,0 +1,161 @@ +--- +title: Alphabet Scroll +slug: alphabet-scroll +url: /blog/alphabet-scroll/ +original_url: https://www.codenameone.com/blog/alphabet-scroll.html +aliases: +- /blog/alphabet-scroll.html +date: '2016-07-17' +author: Shai Almog +--- + +![Header Image](/blog/alphabet-scroll/alphabet-scroll.png) + +We got a lot of requests from developers over the years to do an iOS style alphabet side scroll. Some developers +implements such scrolling but no one made it generic or contributed it back. So a recent stack overflow question +got me thinking about how easy it would be to actually implement something like that and I decided to try…​ + +I ended up building this in 10 minutes and the concept is remarkably simple. I have two containers, one contains +the list of the people and the other one contains the letters used for these people. Notice that I chose to only use +letters that used in the names, I could have just hardcoded the English alphabet but chose to avoid that as this +would break for internationalization and include letters that might not be common in such cases such as ‘Z’. + +Thanks to the usage of layered layout the containers just appear on top of one another, notice that in the sample +code below I had to cancel the default scrollability of the form to allow the two containers to have their own +scrollability. The scrolling isn’t nested in this case since these are two separate containers that just happen +to be one on top of the other. + +We scroll to the selected component by finding it as we loop over the components in the actual container and +using `scrollComponentToVisible` which is pretty convenient for this case. + +**Check out the live demo on the right side thanks to the JavaScript port** + +You can also check out the full project on github [here](https://github.com/codenameone/AlphabetScroll) and see +the relevant code below: + + + String[] characters = { "Tyrion Lannister", "Jaime Lannister", "Cersei Lannister", "Daenerys Targaryen", + "Jon Snow", "Petyr Baelish", "Jorah Mormont", "Sansa Stark", "Arya Stark", "Theon Greyjoy", + "Bran Stark", "Sandor Clegane", "Joffrey Baratheon", "Catelyn Stark", "Robb Stark", "Ned Stark", + "Robert Baratheon", "Viserys Targaryen", "Varys", "Samwell Tarly", "Bronn","Tywin Lannister", + "Shae", "Jeor Mormont","Gendry","Tommen Baratheon","Jaqen H'ghar","Khal Drogo","Davos Seaworth", + "Melisandre","Margaery Tyrell","Stannis Baratheon","Ygritte","Talisa Stark","Brienne of Tarth","Gilly", + "Roose Bolton","Tormund Giantsbane","Ramsay Bolton","Daario Naharis","Missandei","Ellaria Sand", + "The High Sparrow","Grand Maester Pycelle","Loras Tyrell","Hodor","Gregor Clegane","Meryn Trant", + "Alliser Thorne","Othell Yarwyck","Kevan Lannister","Lancel Lannister","Myrcella Baratheon", + "Rickon Stark","Osha","Janos Slynt","Barristan Selmy","Maester Aemon","Grenn","Hot Pie", + "Pypar","Rast","Ros","Rodrik Cassel","Maester Luwin","Irri","Doreah","Eddison Tollett","Podrick Payne", + "Yara Greyjoy","Selyse Baratheon","Olenna Tyrell","Qyburn","Grey Worm","Meera Reed","Shireen Baratheon", + "Jojen Reed","Mace Tyrell","Olly","The Waif","Bowen Marsh" + }; + + Toolbar.setGlobalToolbar(true); + + Form f = new Form("Letter Scroll", new LayeredLayout()); + + f.setScrollable(false); + Container characterContainer = new Container(BoxLayout.y()); + Container lettersContainer = new Container(BoxLayout.y()); + characterContainer.setScrollableY(true); + lettersContainer.setScrollableY(true); + + char lastLetter = 0; + Arrays.sort(characters, new CaseInsensitiveOrder()); + for(String character : characters) { + MultiButton mb = new MultiButton(character); + characterContainer.add(mb); + char c = Character.toUpperCase(character.charAt(0)); + if(c != lastLetter) { + lastLetter = c; + Button btn = new Button("" + lastLetter); + lettersContainer.add(btn); + btn.getAllStyles().setPadding(0, 0, 0, 0); + btn.getAllStyles().setMargin(0, 0, 0, 0); + btn.addActionListener(e -> { + for(Component cmp : characterContainer) { + MultiButton m = (MultiButton)cmp; + if(Character.toUpperCase(m.getTextLine1().charAt(0)) == c) { + characterContainer.scrollComponentToVisible(m); + return; + } + } + }); + } + } + + f.add(characterContainer). + add(BorderLayout.east(lettersContainer)); + + f.show(); +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — July 19, 2016 at 7:39 am ([permalink](https://www.codenameone.com/blog/alphabet-scroll.html#comment-22861)) + +> Chidiebere Okwudire says: +> +> Nice and short! Would it be possible to animate the alphabet list as happens on some phones. So pressing down on the list and scrolling causes the list to kind of bump out around the position? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Falphabet-scroll.html) + + +### **Ross Taylor** — July 19, 2016 at 8:56 am ([permalink](https://www.codenameone.com/blog/alphabet-scroll.html#comment-22644)) + +> Ross Taylor says: +> +> Neat. However when I scroll the list, the title bar disappears and is turned into a blank space. Is this suppose to happen? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Falphabet-scroll.html) + + +### **Chidiebere Okwudire** — July 19, 2016 at 1:29 pm ([permalink](https://www.codenameone.com/blog/alphabet-scroll.html#comment-22818)) + +> Chidiebere Okwudire says: +> +> One more thing: Is there a catalog of these handy features? Something as simple as an appendix in the user manual, for example, that refers to the corresponding blog posts. I don’t know about others but it happens quite often that I want to do something and I remember once reading about it but I’m not sure where and how to find the post quickly. It would be nice if there’s an overview and also make these handy utilties more visible to newcomers. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Falphabet-scroll.html) + + +### **Shai Almog** — July 20, 2016 at 4:20 am ([permalink](https://www.codenameone.com/blog/alphabet-scroll.html#comment-22580)) + +> Shai Almog says: +> +> You can just set the UIID of one of them to selected or even just increase the font or padding so this would be easy and should “just work”. The main challenge is detecting where you are in the scroll. When a user scrolls by pressing a button this should be pretty easy but when the user scrolls via touch this might be more challenging. You can use the scroll listener which should be pretty easy to work with and then hack something with getComponentAt(x, y) to find the location you are currently in. +> +> Another approach which I haven’t tested but might be more elegant is this: +> After constructing and initializing the layout loop over the component and assign a Y range to every alphabet letter. getY() of a specific component should return the right scroll offset and this should work nicely with the scroll listener. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Falphabet-scroll.html) + + +### **Shai Almog** — July 20, 2016 at 4:20 am ([permalink](https://www.codenameone.com/blog/alphabet-scroll.html#comment-22733)) + +> Shai Almog says: +> +> That’s a bug in the JavaScript port, Steve just committed a fix for this. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Falphabet-scroll.html) + + +### **Shai Almog** — July 20, 2016 at 4:23 am ([permalink](https://www.codenameone.com/blog/alphabet-scroll.html#comment-22977)) + +> Shai Almog says: +> +> The problem with that is that someone needs to maintain it and if something doesn’t make it there then people assume it doesn’t exist. Sometimes it’s better off to have nothing than to have something that’s half done. +> +> The thing I’d really like to add to the developer guide is a big section on cn1libs covering usage of the top cn1libs e.g. parse, maps, bouncy castle etc. but I can’t seem to find the time/person to do that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Falphabet-scroll.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/alternative-app-stores.md b/docs/website/content/blog/alternative-app-stores.md new file mode 100644 index 0000000000..805cc4de3d --- /dev/null +++ b/docs/website/content/blog/alternative-app-stores.md @@ -0,0 +1,64 @@ +--- +title: Alternative App Stores +slug: alternative-app-stores +url: /blog/alternative-app-stores/ +original_url: https://www.codenameone.com/blog/alternative-app-stores.html +aliases: +- /blog/alternative-app-stores.html +date: '2015-06-15' +author: Shai Almog +--- + +![Header Image](/blog/alternative-app-stores/alternative-app-stores.jpg) + +Let’s face it, your app is probably a commodity. As noted by [Wikipedia](http://en.wikipedia.org/wiki/Commodity), +“a commodity has full or partial fungibility; +that is, the market treats its instances as equivalent or nearly so with no regard to who produced them.” In basic English +it means that your product can be easily replaced in part or completely by another to satisfy the needs of the market. +For 99% of apps out there this means that if a user doesn’t find your app, they’ll pick another one that they think fills +the need they’re looking to satisfy. This the same whether your app is a game, a productivity app or any other category. + +As the app ecosystem has evolved the challenge of reaching consumers for app developers has grown more and more difficult. +From a technical perspective the promise of reduced fragmentation hasn’t panned out even with so many OSs +already sitting in the graveyard and others staring the grim reaper straight in the eyes. Any app discovery gains +won as a result of consumers migrating to two primary OSs have been swamped by the sheer volume of apps +developed and now available in the main app stores. Imagine walking into Walmart and there being 1 million items stocked on the shelves. How would anyone find your product? + +#### Why the Walmart strategy fails + +In the world of physical products, unless a manufacturer has an established brand or a ton of resources, they don’t +launch their product in Walmart yet every publisher rushes to get their app into iTunes and Google Play. Since +getting on the shelf is the easy part, it’s much more important to get people using your quality app wherever it is they +choose to shop than it is to drive people into the iTunes or Google Play stores. Getting on their shelves is a basic requirement but far from sufficient for success. Remember, your app is a commodity – if it’s not available when and where users are shopping then it’s a missed opportunity. We often hear the question “why does anyone use anything other than Google Play?”. In reality that’s precisely the wrong question to ask. The correct question is “Do you want your app to miss out on the 100s of millions of downloads that are taking place outside of Google Play?” + +Even with a quality app, like any startup business, your odds of being successful aren’t very good. The One Platform Foundation’s +[Android AppStore Market Overview](http://www.onepf.org/appstores/) noted that alternative app stores significantly improve the chances of your app being discovered by consumers. “Submitting your app to alternative appstores will increase your chances of being featured by more than 20 times.” The job of any small business owners is to give their business the best chance to be successful in a highly competitive marketplace. This has never been more important than for app publishers today. + +#### Don’t ignore the global audience + +Being everywhere really means “Think global – act local”. Do not forget about language localization and the importance of this. +[Case studies from online gaming](http://blog.xsolla.com/2014/03/05/localization/) has shown +that bounce rates can drop significantly and conversion and revenue drastically. For instance, 5% of the apps in Russia are localized, yet generate +[70% of the revenue](http://blog.codengo.com/2012/07/going-local-the-importance-of-language-for-mobile-app-revenues/). + +Finally, alternative app stores are here to stay. Why, you might ask, with Google and Apple holding such a monopoly? App stores are a key piece of the strategic plan for companies like Amazon, Nokia, Yandex, Samsung, Baidu and the list goes on. They’re investing in app stores for the long run. + +#### So what should you be doing? + +You probably can’t ignore paid promotion at some point, but the truth here is that +[costs are rising exponentially](http://www.gamesindustry.biz/articles/2015-05-29-mobile-marketing-costs-continue-to-rise-exponentially). +Another way out is to make sure your app is in as many stores as possible. +[CodeNgo helps you with that](http://www.codengo.com/features/?utm_source=codenameone&utm_medium=guestpost&utm_campaign=altappstorespost). +For less than $1 store you’ll have shelf space in the 7’11 of app stores – or the Safeway, perhaps even +“near the cash register” (i.e. front page). That is a huge improvement from the back of the warehouse in Google Play. +Apple and Google aren’t going anywhere soon but their grip on the consumer will lessen over time. + +It’s about the consumer, not the store. Be where the consumers are. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/always-on-top-style-parser.md b/docs/website/content/blog/always-on-top-style-parser.md new file mode 100644 index 0000000000..5e6666e41b --- /dev/null +++ b/docs/website/content/blog/always-on-top-style-parser.md @@ -0,0 +1,45 @@ +--- +title: Always on Top and Style Parser +slug: always-on-top-style-parser +url: /blog/always-on-top-style-parser/ +original_url: https://www.codenameone.com/blog/always-on-top-style-parser.html +aliases: +- /blog/always-on-top-style-parser.html +date: '2017-09-24' +author: Shai Almog +--- + +![Header Image](/blog/always-on-top-style-parser/new-features-2.jpg) + +It’s been a busy week with 3.7.3 released and a lot of new things. [Diamond](https://github.com/diamondobama) made several [PR’s](https://github.com/codenameone/CodenameOne/pulls) over the past couple of weeks but one interesting PR is an “always on top” feature for the simulator which is exactly what it sounds…​ + +This is very useful for me personally as it will allow me to film coding while showing the simulator floating on top (thanks Diamond!) but it should be super useful for everyone. You can inspect the code/debugging values while the simulator floats on top. You can activate it using the simulator menu option. + +### Style Parser + +Styles are a pretty complex and deeply ingrained subject in Codename One. It’s really hard to extend or modify this without breaking everything…​ + +Steve recently ventured on the surface and offered a new way in thru a String based style syntax that is a hybrid of CSS and Codename One logic. Don’t confuse this with the CSS plugin. The CSS plugin works statically during compile time and Codename One is “unaware” of its existence. The resulting file in the CSS file is a regular CSS file. + +This new style mode is builtin to Codename One and overrides styles defined in the theme. This is useful for the GUI builder where you might want to customize the appearance of a component without venturing into the theme and creating a new UIID. + +You can use this from code and might find some pretty cool hacks for it but this was built mostly to facilitate styling directly from the GUI builder. This can be used in the new GUI builder UI in the 3rd tab where you can now customize styles for components directly: + +![Style customization from within the GUI builder](/blog/always-on-top-style-parser/gui-builder-style-editor.png) + +Figure 1. Style customization from within the GUI builder + +This is a new feature so some things might now work for the 3.7.3 release. Please let us know in the [issue tracker](http://github.com/codenameone/CodenameOne/issues/) + +__ | In the current version there is a bug that might require you to close and reopen the UI for the styling to work +---|--- + +As a sidenote the new GUI builder and autolayout mode have improved significantly since 3.7.2 and are far more pleasurable to use! + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/analysis-google-moving-to-openjdk-what-that-really-means.md b/docs/website/content/blog/analysis-google-moving-to-openjdk-what-that-really-means.md new file mode 100644 index 0000000000..09567fb2c4 --- /dev/null +++ b/docs/website/content/blog/analysis-google-moving-to-openjdk-what-that-really-means.md @@ -0,0 +1,280 @@ +--- +title: 'Analysis: Google Moving to OpenJDK, What That Really Means' +slug: analysis-google-moving-to-openjdk-what-that-really-means +url: /blog/analysis-google-moving-to-openjdk-what-that-really-means/ +original_url: https://www.codenameone.com/blog/analysis-google-moving-to-openjdk-what-that-really-means.html +aliases: +- /blog/analysis-google-moving-to-openjdk-what-that-really-means.html +date: '2015-12-29' +author: Shai Almog +--- + +![Header Image](/blog/analysis-google-moving-to-openjdk-what-that-really-means/dukeandroid.png) + +I’ve been following the news breaking since yesterday as +[a hacker news post](https://news.ycombinator.com/item?id=10803775) +highlighted that an Android commit included OpenJDK files. This is amazing news and a huge step forward +for Java, its still unclear if this is just another move or the inkling of a settlement between Google and +Oracle but I’m very hopeful that this is indeed a settlement. So far Google wouldn’t comment on the +court case and [ +whether it was settled since its still ongoing.](http://venturebeat.com/2015/12/29/google-confirms-next-android-version-wont-use-oracles-proprietary-java-apis/) +**Disclaimer:** I worked at Sun/Oracle but had no internal knowledge of any of the things +discussed here. The information here is collected from public sources, my understanding of the mentality of +said companies & from our following the case at [Codename One](/) (we consulted IP lawyers quite a bit +when we started and this case was always on our mind). + +I’ve read a lot of the comments in the reddit & hacker news threads and they seem to include a few upvotes +on comments that are just plainly wrong here is a brief FAQ/informational on these common misquotes. + +#### Android will move to Hotspot/JIT + +That’s unlikely. Java compatibility and compliance with OpenJDK doesn’t require that you use the JIT that ships +with it or any of its source code for that matter. Quite a few compliant implementations don’t. +While Hotspot will probably beat ART for anything other than startup time performance on mobile is quite +different than desktop performance. Battery life is more crucial than speed and I doubt hotspot is +optimized for that. + +#### Swing/AWT/FX Will Finally Be Supported On Android + +There is no indication of that and it seems very unlikely. +Google can be Java compliant by supporting a subset of Java and this is even easier thank to the modularity +changes in Java 9. Swing/AWT/FX compliance complicate this whole process to a completely different level. + +#### Google Was At Fault + +There were several claims like this e.g. Google copied code etc. +I don’t like the fact that Android isn’t Java compatible and forked, but I generally disagree with that statement. +It might have been wrong “morally” to fork Java, but I don’t think it was wrong legally. +In the discovery phase of the trial only one small method was shown to be a direct copy and the judge +dismissed that as ridiculous. +Google didn’t violate the trademarks of Java and the coffee cup which are an important tool to keep Java clean. +E.g. they never claimed that Android runs Java, it runs Android/Dalvik and now ART. It compiles Java source code +which is a big leap. +The claim is about copyrighting the API, that’s a problematic claim since Google did use a clean room implementation +of the public API’s. The supreme court effectively said that clean room implementations of public API’s are +illegal! + +That’s a pretty bad thing since copyright is implicit. Its owned even if the person publishing the material doesn’t +explicitly write that little (c) you see next to various types of work. So if you ever implemented an API you are +now effectively using copyrighted code! + +Most programmers who understand this think that Google acted based on “fair use” which means they didn’t +actually violate the rights of the copyright holder. + +#### Oracle is a greedy litigious company + +Not really. +Oracle does sue companies but generally larger companies that can afford this, I’m unaware of them suing +a startup or other small companies (feel free to correct me if I’m wrong here). It is far more profit driven than +Sun was. I really loved Sun and loved working there, I can’t say the same about Oracle… +But to be totally fair, Sun no longer exists in part because it was mismanaged and maybe not “greedy” enough. +Having a strong “landlord” for Java might be disturbing in some regards but it has its advantages. I think +anyone trying to show Oracle off as “evil” is plain wrong. + +#### This is like the Microsoft Lawsuit + +No. +Microsoft was a Java licensee and took the code to create a non-compliant implementation. Google was +a licensee but the Android division was not. The fact that Google was a licensee for Java didn’t factor into +the trial to my non-lawyer knowledge. + +#### This is about Java Compatibility + +While Java compatibility is important and Google did do some damage there (not as much as the lawsuit did but +still), this wasn’t the reason for the case. +The lawsuit originally mentioned a 6bn USD figure for compensation and Google was willing to pay 100M USD +to settle… This was like most lawsuits are about money. +Its not necessarily bad to sue about money but this clearly cost more than it should have for both sides as +it hurt Java in the market and that hurt two of its biggest users (Oracle & Google). Sun used to make +a per device license fee for every J2ME phone sold, that was a huge bucket of money. I think Sun lost +that revenue stream because it just neglected to update J2ME for more than a decade and when it finally did it +was way too late. + +#### Is This Good For Java? + +Yes. Without a question! +Some claim the lawsuit should have been decisively won by Google, I think that would have been great because +as stated above I don’t think the copyright clause is good for the industry as a whole. But that ship has sailed +and now the best thing for Java is ending the hostility and unifying behind one standard Java so its great. + +Furthermore, ending this hostility means Java proved its chops in court which is a huge milestone. Developers +often have the justify-able backlash when the legal system is involved choosing to go with a technology that’s +more open (e.g. WebAssembly). Technologies like that might have hidden elements that can be +sued over that we aren’t even aware of e.g. just using a GIF file was ground for legal action a few years ago… +This is problematic with more open standards as there isn’t a single “landlord” to carry the technology forward +in such a court case. + +Java has seen quite a few days in court and one of the nice things about OpenJDK is that it includes a patent +license provision. This is rare and really valuable, if Google and Oracle settle over OpenJDK it pretty much means +we can all align behind it peacefully and litigation would become far less likely. + +Furthermore, I think this would be great for Android as it will eventually move to a newer more modern version +of Java and might enjoy better tooling as a result. It would also mean that some optimizations that might have +been avoided by Android’s Runtime due to potential patent litigation might be applied to ART leading to +additional benefits. + +The reduced stress among Google developers about IP cleanliness could also boost the productivity at Google +and allow the Android developers to focus on building a better product. + +#### What About Older Versions of Android? + +For those we will be able to use something like retrolambda like we do in Codename One. + +#### How Will This Affect Codename One? + +Right now we tried to avoid OpenJDK code as much as possible with the same basic thought pattern Google +took of using a clean room implementation to protect ourselves from future IP claims. +We are following this closely, if this happens we’ll align ourselves to be compliant with CLDC 8 which is +a valid Java 8 subset. This shouldn’t require much works as we are already 50% there and +[ParparVM](https://github.com/codenameone/CodenameOne/tree/master/vm) +etc. should be trivial to move to that level of compliance. + +This would hopefully give us a path to move forward in a way that would keep everyone happy. + +#### Summary + +This is great news for all Java developers everywhere! +Whether you work on Android, server, mobile or desktop! +This could be the start of the long anticipated “peace process” or at least a ceasefire between Google & Oracle. +This could allow us all to align behind one Java version eventually (taking into consideration the slow Android +update process). It could help bring Java back into vogue with some developers who considered the closed +nature of Java problematic. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Luix** — December 30, 2015 at 2:26 pm ([permalink](https://www.codenameone.com/blog/analysis-google-moving-to-openjdk-what-that-really-means.html#comment-22616)) + +> Luix says: +> +> Re: “is it good for Java?” The main issue here is Java isn’t good enough for anyone. Most of the apps running in that resource hog are chucks of code blindly stolen from previous apps/programs. Most of the developers just steal the code and mend it to perform more or less decently, and when that’s not enough, they just simply demand more hardware. +> +> I don’t mean to start a flame war, but IMHO Google should ditch the Java approach all together and find a better replacement. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanalysis-google-moving-to-openjdk-what-that-really-means.html) + + +### **Shai Almog** — December 30, 2015 at 2:31 pm ([permalink](https://www.codenameone.com/blog/analysis-google-moving-to-openjdk-what-that-really-means.html#comment-22626)) + +> Shai Almog says: +> +> You don’t mean to start a flame war but you post a “Java sux” comment in a Java blog. And with a Darth Vader avatar no less 😉 +> +> Copy and paste == code reuse. Bad programmers exist everywhere. Java is actually pretty efficient (e.g. embedded etc.) and performant when compared to pretty much all alternatives. +> +> Google analyzed the options before picking Java, there are no realistic alternatives for Java and none are better performing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanalysis-google-moving-to-openjdk-what-that-really-means.html) + + +### **Luix** — December 30, 2015 at 2:44 pm ([permalink](https://www.codenameone.com/blog/analysis-google-moving-to-openjdk-what-that-really-means.html#comment-22636)) + +> Luix says: +> +> An excellent answer. I apologize, English isn’t my main language. Java *was* the best alternative when Android started walking its first steps, but then again, a lot of water has gone below that bridge. +> +> As a SysAdmin I deal with poorly written Java code all the time (i.e. the developers simply complain about their code running slow on expensive hardware because they don’t have enough resources). I’d like to see a path to better resource usage rather than expecting the system to grow in size. That’s just an unrealistic approach. I reckon it’s Google’s fault for not steering the development in that direction, but then again, Java might be the de facto standard, but it doesn’t mean it couldn’t be improved. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanalysis-google-moving-to-openjdk-what-that-really-means.html) + + +### **Shai Almog** — December 30, 2015 at 2:53 pm ([permalink](https://www.codenameone.com/blog/analysis-google-moving-to-openjdk-what-that-really-means.html#comment-22456)) + +> Shai Almog says: +> +> We discussed this a bit in the hacker news thread. One of the problems with Java on the server/desktop is the lack of MVM (or isolates as they are called today) which allows multiple Java instances to share more state and thus take up less RAM/CPU. Back in the day this wasn’t a priority for Sun as it was selling big iron hardware and it would just mean “buy more hardware”. +> +> I totally see the issues you are running against, some Java apps are just ridiculous and its often hard for us to gauge what the hell is needed in terms of resources. One annoyance I had with servers was that the Xmx switch for the JVM to indicate the maximum memory has no value for the admin. It only allocates the memory visible to the Java application but not the memory I need to give to the server. So if I use -Xmx2gb the app might take up 2.5gb because of various VM overhead issues. This makes it pretty painful, but that’s an implementation problem more than an inherent issue in the Java language. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanalysis-google-moving-to-openjdk-what-that-really-means.html) + + +### **Luix** — December 30, 2015 at 3:01 pm ([permalink](https://www.codenameone.com/blog/analysis-google-moving-to-openjdk-what-that-really-means.html#comment-21500)) + +> Luix says: +> +> Again, I appreciate the time you took to make me a little less ignorant. +> +> Like you said, a language isn’t inherently bad or good, it’s the use we give to it what draws a positive/negative value. +> +> Anyway, I salute the step Google took to a open source implementation, and agree with you in your considerations about what that means in terms of growth for the community and the language itself. I just hope Google would tighten the development guidelines the way they did with the visual ones with Material Design. +> +> All I have left are my best wishes for the upcoming new year. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanalysis-google-moving-to-openjdk-what-that-really-means.html) + + +### **bryan** — January 2, 2016 at 10:10 pm ([permalink](https://www.codenameone.com/blog/analysis-google-moving-to-openjdk-what-that-really-means.html#comment-22440)) + +> bryan says: +> +> What you said makes no sense at all. Java the language is fine (unless your preference is functional languages), and the JVM (which as Shai has noted is NOT what Google use) works just fine also. Back in the day almost all feature phones had Java baked in, and given the hardware constraints, Java apps worked remarkably well (and worked even better with LWUIT – thanks Shai/Chen), so to say Java is intrinsically slow or a resource hog is nonsense. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanalysis-google-moving-to-openjdk-what-that-really-means.html) + + +### **Adam** — January 6, 2016 at 7:19 pm ([permalink](https://www.codenameone.com/blog/analysis-google-moving-to-openjdk-what-that-really-means.html#comment-22657)) + +> Adam says: +> +> “While Hotspot will probably beat ART for anything other than startup time performance on mobile is quite different than desktop performance. Battery life is more crucial than speed and I doubt hotspot is optimized for that.” +> +> Are these really competing goals? Something that executes in fewer CPU cycles will result in longer battery life. AOT is always better than JIT for most things (unless they can only be known at runtime), but as far as a JIT engine goes, faster is better for everybody. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanalysis-google-moving-to-openjdk-what-that-really-means.html) + + +### **Shai Almog** — January 6, 2016 at 7:30 pm ([permalink](https://www.codenameone.com/blog/analysis-google-moving-to-openjdk-what-that-really-means.html#comment-22514)) + +> Shai Almog says: +> +> Not quite so simple… we have two cases: +> +> a. Really complex calculations that take up 100% of the CPU. JIT has the advantage of determining all the branches that never change and optimizing them away. Inlining methods more aggressively etc. +> +> b. Most apps – cpu is needed for very short bursts and idle afterwards. JIT has plenty of CPU cycles left to optimize the short bursts to be much faster/smaller. On mobile devices this is good since it makes better use of CPU caches. +> +> AOT will always be slower than a good JIT since it has no way of optimizing away a branch statement that never changes. These are really expensive. Virtual method inlining (which leads to cross method optimizations) is also a HUGE benefit. +> +> Reducing battery usage is a different deal though and memory constraints on the device are also different. A jit can over optimize and regress. It can choose to use IDLE CPU to do various tasks which when optimized for power consumption it won’t. At Sun we had several very different JIT implementations, the mobile JIT’s had a far simpler architecture than hotspot. You even see this in the two modes hotspot features (server & client). +> +> Anyway, I digress. Its a bit more complex than that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanalysis-google-moving-to-openjdk-what-that-really-means.html) + + +### **Adam** — January 6, 2016 at 7:46 pm ([permalink](https://www.codenameone.com/blog/analysis-google-moving-to-openjdk-what-that-really-means.html#comment-22257)) + +> Adam says: +> +> Yes, a lot of that fits into my “unless they can only be known at runtime” parenthetical there, and I agree, there are limits to ahead of time compilation where a JIT can do much better. +> +> That being said, what on earth would the JIT be doing that is consuming otherwise idle CPU cycles that aren’t otherwise necessary tasks? Overly aggressive garbage collection? Maybe I’m only looking at this from an application level lens when I should be viewing from a virtual machine lens. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanalysis-google-moving-to-openjdk-what-that-really-means.html) + + +### **Shai Almog** — January 6, 2016 at 7:55 pm ([permalink](https://www.codenameone.com/blog/analysis-google-moving-to-openjdk-what-that-really-means.html#comment-22664)) + +> Shai Almog says: +> +> Think of a JIT as a profiler that runs on your device in your users hands. +> +> The profiler ran while the user used the application, since every user uses the app differently the JIT has an option to optimize based on how the user worked and idle is the perfect time to do it. +> +> Hotspot will further optimize but needs to decide when to stop and also when to revert an optimization that didn’t generate the right results (optimizations aren’t always clean cut). +> +> Mobile JIT’s aren’t as aggressive but they do something weird. They GC jitted code. E.g. if RAM is low or if a piece of code was used a few times and then no longer called then wasting RAM on compiled code is redundant. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanalysis-google-moving-to-openjdk-what-that-really-means.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/android-app-bundle-support.md b/docs/website/content/blog/android-app-bundle-support.md new file mode 100644 index 0000000000..f3b6775d03 --- /dev/null +++ b/docs/website/content/blog/android-app-bundle-support.md @@ -0,0 +1,82 @@ +--- +title: Android App Bundle Support +slug: android-app-bundle-support +url: /blog/android-app-bundle-support/ +original_url: https://www.codenameone.com/blog/android-app-bundle-support.html +aliases: +- /blog/android-app-bundle-support.html +date: '2021-05-08' +author: Shai Almog +description: We have added Android App Bundle support which will become the required + format for submitting apps to Google Play. +--- + +We have added Android App Bundle support which will become the required format for submitting apps to Google Play. + +A few months ago, we added Android App Bundle support and forgot to tell anyone... These things sometimes happen in a fast-moving startup… Well, better late than never. + +To try the App Bundle support, use the build hint: android.appBundle=true + +This will produce the regular APK and the app bundle file which you should be able to upload to Google. + +### What is Android App Bundle? + +For those who aren’t aware… Android App bundle is a new format designed by Google to replace the venerable APK. + +It isn’t much different but is generally better suited for splitting so different versions can be sent to different devices more easily. + +This makes sense for very fat applications, not so much for Codename One apps which are usually leaner than native Android apps. + +In August, Android App Bundle will become the required format for submitting to Google Play. In a couple of weeks we will flip the default so the app bundle build hint will be true implicitly. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved here for historical context. New discussion happens in the Discussion section below._ + + +### **Francesco Galgani** — June 6, 2021 at 12:57 pm ([permalink](https://www.codenameone.com/blog/android-app-bundle-support.html#comment-24464)) + +> Francesco Galgani says: +> +> Since the aab format is not installable on an Android smartphone but can only be used to publish in the store, you will always continue to provide the apk format, right? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-app-bundle-support.html) + + +### **Shai Almog** — June 6, 2021 at 2:01 pm ([permalink](https://www.codenameone.com/blog/android-app-bundle-support.html#comment-24466)) + +> Shai Almog says: +> +> I won’t say “always” since things change but as long as AAB isn’t installable you will need an APK and we’ll provide it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-app-bundle-support.html) + + +### **Chris Vorster** — September 11, 2021 at 12:56 am ([permalink](https://www.codenameone.com/blog/android-app-bundle-support.html#comment-24479)) + +> Chris Vorster says: +> +> Trying to upload a new version of the AAB on Google Dev Console results in signing error. Cannot find a way to fix this, tried support also. +> “Your Android App Bundle is signed with the wrong key. Ensure that your App Bundle is signed with the correct signing key and try again. Your App Bundle is expected to be signed with the certificate with fingerprint:…” +> +> Can’t seem to find any solutions on how to deal with this. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-app-bundle-support.html) + + +### **Lianna Casper** — September 11, 2021 at 4:12 am ([permalink](https://www.codenameone.com/blog/android-app-bundle-support.html#comment-24480)) + +> Lianna Casper says: +> +> You need to pick the right keystore in Codename One Settings. How did you sign the app you first uploaded? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-app-bundle-support.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/android-build-target-27-migration.md b/docs/website/content/blog/android-build-target-27-migration.md new file mode 100644 index 0000000000..62c5126866 --- /dev/null +++ b/docs/website/content/blog/android-build-target-27-migration.md @@ -0,0 +1,299 @@ +--- +title: Android Build Target 27 Migration +slug: android-build-target-27-migration +url: /blog/android-build-target-27-migration/ +original_url: https://www.codenameone.com/blog/android-build-target-27-migration.html +aliases: +- /blog/android-build-target-27-migration.html +date: '2018-03-27' +author: Shai Almog +--- + +![Header Image](/blog/android-build-target-27-migration/android_studio.jpg) + +A while back [Google announced](https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html) that starting in August 2018 they will no longer accept applications targeting API levels below 26. With that in mind we plan to migrate our builds to use API level 27 which brings with it a lot of great new features but will probably break some things as we go through the migration. Please read this post carefully, I’ll try to cover everything. + +Notice that this announcement means that we will need to start updating the API levels every year which is a much faster pace. + +I’ve constructed this post as a set of questions/answers. + +### What’s an API Level? + +Every time Google releases a new version of Android it updates the API level e.g. currently Oreo (8.1) is API level 27. + +When we build a native Android application we need to declare the “target” this means we compiled the project against this given API level. This is a double edged sword…​ When we pick a higher API level we can target new features of newer OS’s but we are also subject to new restrictions and changes. + +E.g. when we migrated to API level 23 we had to change the way permissions are processed in applications. For Codename One code this was mostly seamless but if you relied on native code this sometimes triggered issues. + +API level 27 can impact things such as background behavior of your application and can break some cn1libs/native code you might have in place. + +FYI this is also explained in this [article](https://arstechnica.com/gadgets/2017/12/google-fights-fragmentation-new-android-features-to-be-forced-on-apps-in-2018/) from Ars. + +### Will this Work for Older Devices? + +The target API level doesn’t restrict older devices. For that we have a separate minimum target device and it indicates the lowest API level we support. Currently the default is 15 (Android 4.0.3 – Ice Cream Sandwich) but you can probably set it as low as 9 (Android 2.3 – Gingerbread) as long as you test the functionality properly and disable Google Play Services. + +See [this](https://developer.android.com/guide/topics/manifest/uses-sdk-element.html) for a table of all the API levels from Google. + +### What API Level do we use Now? + +That depends on your app. Our default is 23 but some cn1libs set the API level to 25. + +We chose to migrate slowly as level 23 is generally good and stable. + +### Test This Now! + +**Test API level 27 right now before we flip the switch!** + +This is important as we want to iron out bugs/regressions before they impact everyone. You can enable this seamlessly by setting the build hint: `android.buildToolsVersion=27` + +__ | Remove this build hint after testing, otherwise when we migrate to a newer version later on it might fail! +---|--- + +This will implicitly set a lot of other values including the target level and it will change the gradle version from 2.12 to 4.6. + +#### Other Benefits. + +By flipping this switch the build should now work on Android Studio 3.x out of the box without the changes listed in [this tip](/blog/tip-include-source-android-studio-3.html). We also plan to enable other things in the resulting project such as using Googles builtin Java 8 support instead of ours (this isn’t enabled yet). + +This will mean that native Android code would be able to use Java 8 features. Notice that this currently applies to the native interfaces only and not to the code in the Codename One implementation. + +This should make it easier to work with some 3rd party libraries that already moved forward. + +### When Will this Happen? + +The 27 build target is available now using the build hint: `android.buildToolsVersion=27`. + +Currently we are aiming to flip the switch by May. This might be pushed to a different date based on responses/feedback on the current status. We want to have enough time ahead so the July release of Codename One 5.0 (Social) will use this. + +### Is this a Good Thing? + +I think it is. It prevents stagnation within the appstore. + +I still see apps in the stores that target Gingerbread (API level 9). That’s a problem both visually & in terms of permissions/security. + +I don’t think it will do enough to combat fragmentation. Google will need to change a lot more to fix that pickle but it’s a baby step in the right direction. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — April 6, 2018 at 9:56 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23555)) + +> Francesco Galgani says: +> +> I’ve done some tests with “android.buildToolsVersion=27” in Android 7 and Android 5 devices and I didn’t notice any difference 🙂 +> However, I don’t understand why the target API level doesn’t restrict older devices: if the API 27 is for Android 8.1, how is it possible that the older devices are supported? Is it possible because Codename One build servers don’t generate code that is supported only by recent devices? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Shai Almog** — April 7, 2018 at 4:42 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23648)) + +> Shai Almog says: +> +> Good to hear. +> +> This is a feature from native Android not us. There are 2 different values: minimum API level and Target API level. +> +> When we use a feature from API 27 we check if the device supports API 27 first then call it. This means it will still work on an API 15 device without a problem. +> +> This is a “statement” from the app to the runtime environment saying we tested on an Android 8 device. That means that Google will enable small incompatible changes to Android once this is set. A good example is background behavior which will now be more aggressive. +> +> E.g. In API 23 (Andoid 6) Google introduced a new permission system. +> +> So if you had an Android 5 device and installed an app compiled with target 23 it would still work and show the permission prompt during install. +> +> If you have an Android 6 device and installed an old app (target smaller than 23) it would behave like an Android 5 device and show permissions during install. +> +> However, if both the app and the device are API 23 or newer the app would install instantly and prompt for permissions in runtime. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Denis** — May 12, 2018 at 8:45 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23780)) + +> Denis says: +> +> Hi Shai, +> +> I have put android.buildToolsVersion=27 in build hints, however when I upload apk to Play Console, it warns that app still targets API 23, could you please take a look at screenshots and advise ? +> +> Thanks, +> Denis +> +> [https://uploads.disquscdn.c…]() [https://uploads.disquscdn.c…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Shai Almog** — May 13, 2018 at 4:25 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23692)) + +> Shai Almog says: +> +> Hi, +> what do you have within your [codenameone_settings.proper…](?) It looks like this isn’t passing through. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Denis** — May 13, 2018 at 6:38 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23725)) + +> Denis says: +> +> Hi, +> codename1.arg.android.buildToolsVersion=27 is there, so it looks correct as I understand, please confirm +> Thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Shai Almog** — May 14, 2018 at 4:25 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-21475)) + +> Shai Almog says: +> +> Hi, +> yes. But other build hints might collide with this functionality so are there other android.* build hints in the file? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Denis** — May 14, 2018 at 7:24 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23556)) + +> Denis says: +> +> Hi Shai, +> +> yes, that makes, I don’t know why I haven’t post entire file right away )) +> here it is, take a look please +> +> [android.playService.ads]()=true +> codename1.android.keystore=XXXXXXXXXXXXXXXXXXXXX +> codename1.android.keystoreAlias=XXXXXXXXXXXXXXXX +> codename1.android.keystorePassword=XXXXXXXXXXXXX +> codename1.arg.android.buildToolsVersion=27 +> codename1.arg.android.debug=false +> codename1.arg.android.licenseKey=XXXXXXXXXXXXXXX +> codename1.arg.android.release=true +> codename1.arg.android.statusbar_hidden=true +> codename1.arg.android.xapplication= +> codename1.arg.ios.add_libs=AdSupport.framework;SystemConfiguration.framework;CoreTelephony.framework +> codename1.arg.ios.newStorageLocation=true +> codename1.arg.ios.objC=true +> codename1.arg.ios.pods=,Firebase/Core,Firebase/AdMob +> codename1.arg.ios.pods.platform=,7.0 +> codename1.arg.ios.pods.sources=, +> codename1.arg.ios.statusbar_hidden=true +> codename1.arg.java.version=8 +> codename1.displayName=XXXXXXXXXXXXXXXXXXXXXXXXXX +> codename1.icon=icon.png +> codename1.ios.certificate= +> codename1.ios.certificatePassword= +> codename1.ios.provision= +> codename1.j2me.nativeTheme=nativej2me.res +> codename1.languageLevel=5 +> codename1.mainName=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX +> codename1.packageName=com.manyukhin.XXXXXXXXXXXX +> codename1.rim.certificatePassword= +> codename1.rim.signtoolCsk= +> codename1.rim.signtoolDb= +> codename1.secondaryTitle=XXXXXXXXXXXXXXXXXXXXXXX +> codename1.vendor=Denis Manyukhin +> codename1.version=1.11 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Shai Almog** — May 15, 2018 at 4:08 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23790)) + +> Shai Almog says: +> +> Thanks, +> it looks like you are missing codename1.arg. before the [android.playService.ads]() but that’s unrelated. +> +> Looking again at the code I think you might need to explicitly specify android.sdkVersion=27 for this to work. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Denis** — May 15, 2018 at 4:25 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23960)) + +> Denis says: +> +> Thanks Shai, +> Soo, I should put sdkVersion build hint in [codenameone_settings.proper…](), right ? +> +> also it’s better to move [android.playService.ads]() below Android build hints, is that correct ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Shai Almog** — May 15, 2018 at 4:48 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-21644)) + +> Shai Almog says: +> +> If you edit [codenameone_settings.proper…]() you need to prefix it with codename1.arg. I suggest using the Codename One Setting UI under “Build Hints” to edit these and not edit the file directly. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Denis** — May 15, 2018 at 6:44 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23699)) + +> Denis says: +> +> I have added android.sdkVersion=27 to Build hints via corresponding UI, it appears as codename1.arg.android.sdkVersion=27 in [codenameone_settings.proper…](), +> but still the same warning in Google Play Console, app targeted to API 23, any ideas ? +> +> also I can’t see “[android.playService.ads]()=true” in Build Hints UI, it only appears in [codenameone_settings.proper…](), is it ok ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Denis** — May 15, 2018 at 9:20 pm ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23716)) + +> Denis says: +> +> have you meant android.targetSDKVersion build hint ? +> if not, may be it worth to set android.targetSDKVersion value explicitly ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Shai Almog** — May 16, 2018 at 5:56 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23767)) + +> Shai Almog says: +> +> Does targetSDKVersion solve this issue? +> There is a bit of a mess of build hints here, we should clean it up a bit and ideally expose them in the Android section of Codename One Settings. +> +> Only things with the codename1.arg. prefix will appear in the build hints UI so that flag is effectively ignored. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Denis** — May 16, 2018 at 6:16 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23693)) + +> Denis says: +> +> yes, android.targetSDKVersion solved the issue, no target API warnings, wondering if I shall keep android.sdkVersion and android.buildToolsVersion records in build hints +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + + +### **Shai Almog** — May 17, 2018 at 11:05 am ([permalink](https://www.codenameone.com/blog/android-build-target-27-migration.html#comment-23931)) + +> Shai Almog says: +> +> We’ll switch all of these to default to 27 probably next weekend. I want to give this enough time before we release 5.0 in July. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-build-target-27-migration.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/android-gradle-build-status-minor-changes.md b/docs/website/content/blog/android-gradle-build-status-minor-changes.md new file mode 100644 index 0000000000..a4029a2999 --- /dev/null +++ b/docs/website/content/blog/android-gradle-build-status-minor-changes.md @@ -0,0 +1,65 @@ +--- +title: Android Gradle Build Status & Minor Changes +slug: android-gradle-build-status-minor-changes +url: /blog/android-gradle-build-status-minor-changes/ +original_url: https://www.codenameone.com/blog/android-gradle-build-status-minor-changes.html +aliases: +- /blog/android-gradle-build-status-minor-changes.html +date: '2016-02-08' +author: Shai Almog +--- + +![Header Image](/blog/android-gradle-build-status-minor-changes/gradle.png) + +I’ve been remarkably busy working on issues and documentation so I neglected an important announcement I +had to make. Over the weekend we flipped the default build from gradle back to ant. So effectively if you don’t set +any build hint the behavior will be `android.gradle=false` which should work fine for most of you. This is temporary but +we felt it was necessary as a stopgap measure. + +In other news it seems that fixing the Codename One documentation is like diving into a bottomless pit. +When we started this effort the developer guide was 300 pages it is now approaching 500 pages and we +aren’t close to half way thru…​ + +This doesn’t even cover all the work we did with refining the JavaDocs and there is a lot of work that needs doing +on that side of the fence. + +During this time I’ve made a conscious effort not to do anything significant that isn’t documentation writing but +some code had to go thru. Specifically things related to syntax that needed doing for the developer guide. + +### CheckBox Toggle Syntax + +Up until now we had terse syntax for creating a toggle button for a `RadioButton` but we didn’t have anything +like that for the `CheckBox`. So we added a couple of methods: + + * [createToggle(Image icon)](https://www.codenameone.com/javadoc/com/codename1/ui/CheckBox.html#createToggle-com.codename1.ui.Image-) + + * [createToggle(String text)](https://www.codenameone.com/javadoc/com/codename1/ui/CheckBox.html#createToggle-java.lang.String-) + + * [createToggle(String text, Image icon)](https://www.codenameone.com/javadoc/com/codename1/ui/CheckBox.html#createToggle-java.lang.String-com.codename1.ui.Image-) + +### ButtonGroup Shortcut + +Up until now creating a `RadioButton` required adding it to a `ButtonGroup` which was tedious. + +To solve this we added a varargs +[addAll(Component…​)](https://www.codenameone.com/javadoc/com/codename1/ui/ButtonGroup.html#addAll-com.codename1.ui.RadioButton…​-) +method as well as a [varargs constructor](https://www.codenameone.com/javadoc/com/codename1/ui/ButtonGroup.html#ButtonGroup-com.codename1.ui.RadioButton…​-). + +### ComponentGroup enclose + +`ComponentGroup` didn’t have an `enclose` method which is one of those things that beg for a fix since its **the** +`Container` for that sort of API. + +So we added two enclose methods: + + * [enclose(Component…​)](https://www.codenameone.com/javadoc/com/codename1/ui/ComponentGroup.html#enclose-com.codename1.ui.Component…​-) + + * [encloseHorizontal(Component…​)](https://www.codenameone.com/javadoc/com/codename1/ui/ComponentGroup.html#encloseHorizontal-com.codename1.ui.Component…​-) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/android-migration-tool.md b/docs/website/content/blog/android-migration-tool.md new file mode 100644 index 0000000000..d014cc73c2 --- /dev/null +++ b/docs/website/content/blog/android-migration-tool.md @@ -0,0 +1,79 @@ +--- +title: Android Migration Tool +slug: android-migration-tool +url: /blog/android-migration-tool/ +original_url: https://www.codenameone.com/blog/android-migration-tool.html +aliases: +- /blog/android-migration-tool.html +date: '2016-07-26' +author: Shai Almog +--- + +![Header Image](/blog/android-migration-tool/profiling-in-android-ios.png) + +It’s tough to pick up a new toolchain like Codename One. There’s so much to learn…​ +A lot of our developers come from the Android world and even though Codename One is much simpler than Android porting the first app to Codename One is still painful. + +We wanted to simplify this process since the day we launched Codename One but as we [explained before](/blog/why-we-dont-import-android-native-code.html), this isn’t simple and the results would “underwhelm”. + +We decided that “underwhelming” isn’t always a bad place to start when you are doing open source work. With that in mind Steve [created an open source project](https://github.com/shannah/cn1-android-importer) to scaffold a new Codename One project from an existing Android native project. + +Notice my choice of words, I chose scaffold instead of migrate. This will not turn an Android project into a Codename One project but rather make the process of getting started slightly easier. It migrates the images & strings. + +It creates GUI builder files (using the new GUI builder) for every layout XML file. Notice that the layout isn’t replicated properly and neither is the proper styling. + +These differ a lot between Android and Codename One and would require at least 6 months of intense work to get right. + +Copying the layout seems deceptively easy on the surface but Android layouts differ considerably. We’d love to simplify that but the level of effort required is beyond our limited resources. We can’t justify the effort without a sense of demand…​ + +In the current version we don’t touch the source or the manifest at all but we could address both of these to some degree as part of the work. + +### Moving This Forward + +That’s where you come in. File issues, RFE’s and let us know that you want progress on this. + +Fork and contribute to Steve’s project and provide samples that we should improve. + +Let your friends know about this project and raise community awareness around it! + +We don’t want to invest significant developer resources on something that won’t gain developer traction so we need your help to get this project off the ground. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Gareth Murfin** — July 27, 2016 at 3:09 pm ([permalink](https://www.codenameone.com/blog/android-migration-tool.html#comment-22786)) + +> Gareth Murfin says: +> +> What a great idea, many Android devs looking to produce iOS ports end up thinking about using Codename One. As you say resources are so very different, I found learning Android GUI dev much harder than learning CN1 GUI dev (but previously I was into Swing, J2ME, LWUIT etc). I think one of the main paradigm shifts that is hard to learn is the lack of “activities”. That is in Android each screen has its own class and it starts to feel nice and correct (more OO/modular or something :)) – and when you go to CN1 it is very strange to have everything more “old school” in one or 2 classes. If it were possible it would be good if each screen in cn1 could actually be a separate class, so when you create an event for postShow or something it doesnt go into statemachine but a class called for example Splash(), and with a method postMain() in there. This would make it far easier to navigate projects and understand them (new coders have been scared of even looking at my gargantuan statemachines, preferring to do a rewrite(!)). Just a suggestion of course, and we could easily do this ourself by simply making calls from StateMachine to custom classes we can make for each screen, which is actually what I am planing on doing in my next cn1 app. Current I mostly have one large statemachine, another class holding the business logic that is called on from statemachine, and then a pile of POJOs. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-migration-tool.html) + + +### **bryan** — July 27, 2016 at 9:08 pm ([permalink](https://www.codenameone.com/blog/android-migration-tool.html#comment-22906)) + +> bryan says: +> +> A class per screen/form is the “new” way to do CN1, and the way the new GUI builder works, so this porting tool would do that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-migration-tool.html) + + +### **Shai Almog** — July 28, 2016 at 4:18 am ([permalink](https://www.codenameone.com/blog/android-migration-tool.html#comment-22706)) + +> Shai Almog says: +> +> Yep. I mentioned this uses the new GUI builder so it’s one form class per layout. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fandroid-migration-tool.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/android-push-changes.md b/docs/website/content/blog/android-push-changes.md new file mode 100644 index 0000000000..a84cd35df8 --- /dev/null +++ b/docs/website/content/blog/android-push-changes.md @@ -0,0 +1,63 @@ +--- +title: Android Push Changes +slug: android-push-changes +url: /blog/android-push-changes/ +original_url: https://www.codenameone.com/blog/android-push-changes.html +aliases: +- /blog/android-push-changes.html +date: '2024-06-08' +author: Steve Hannah +--- + +![](/blog/android-push-changes/4191c4440219cf07f21cdbfd7524bf49.webp-copy.jpg) + +We have made some upgrades to our push notification server API. If you deploy apps to Android and use push notifications, you will need to make a small change to the server-side code that sends the HTTP request to our push server. If you do not send push notifications to Android devices, you can ignore this PSA. + +## The Short Version + +Our Push API now requires a JSON key instead of the old FCM API key. For example, the following is a template for a push notification, (copied from the [push cheatsheet](https://www.codenameone.com/files/push-cheatsheet.pdf)). + + + https://push.codenameone.com/push/push?token=PUSH_TOKEN + &device=DEVICE_ID1&device=DEVICE_ID2&...&device=DEVICE_IDN + &type=PUSH_TYPE{1|2|3|4|5|99|100|101} + &auth=FCM_SERVER_API_KEY + &certPassword=ITUNES_CERT_PASSWORD + &cert=ITUNES_CERT_URL + &body=MESSAGE_BODY + &production=ITUNES_PRODUCTION_PUSH{true|false} + &sid=WNS_SID + &client_secret=WNS_CLIENT_SECRET + +Currently, the `auth` parameter will be set to an FCM API key, it might look something like `auth=AAAABbbbCccDddEeeeFfffGGggHhhhIiiiJjjjKkkkLlllMmmmNnnnOooPppQqqRrrrSsssTttUuuuVvvvWxxxYyyyZzzz` + +You will need to change this parameter to be a URL (reachable by the Codename One push server) to a the JSON key for your service. It will look something like: + + + auth=https%3A%2F%2Fexample.com%2Fsecret%2Fpath%2Fto%2Fservice-account-file.json + +You can find instructions on how to generate this `service-account-file.json` (your JSON key) in the Firebase documentation [here](https://firebase.google.com/docs/cloud-messaging/auth-server#provide-credentials-manually). The following instructions are copied from there: + +**To generate a private key file for your service account:** + +> In the Firebase console, open **Settings > [Service Accounts](https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk)**. +> Click **Generate New Private Key** , then confirm by clicking **Generate Key**. +> Securely store the JSON file containing the key. + +> ## The Slightly Longer Version + +Google deprecated their legacy FCM APIs on June 20, 2023, and will be removing them on June 21, 2024. Our push servers use this API for all push notifications to Android devices, so we were required to [migrate ](https://firebase.google.com/docs/cloud-messaging/migrate-v1)to their new “v1 HTTP API”. This migration involved some non-trivial changes to our push infrastructure, including, but not limited to, changing from using an FCM API key for authentication, to using OAuth2. + +The OAuth2 authentication is more complicated than the old API key flow, as it involves multiple pieces of information, including the client ID, client secret, and project ID. To simplify this, Google encapsulates all of these credentials inside a single JSON file which can be used in an opaque manner via its Firebase SDKs. + +On our side, we wanted to avoid unnecessary changes to our API to make this transition as seamless as possible for our users, so we haven’t added or removed any parameters from the request. We just changed the `auth` parameter to include the URL to your `service-account-file.json`, instead of an FCM API key. We chose not to include the whole JSON file contents in each request because the JSON file tends to be quite large and presents unnecessary a network overhead. + +We may iterate on this approach in a non-breaking way based on user feedback. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/androids-permissions.md b/docs/website/content/blog/androids-permissions.md new file mode 100644 index 0000000000..b6a00c6e68 --- /dev/null +++ b/docs/website/content/blog/androids-permissions.md @@ -0,0 +1,63 @@ +--- +title: Androids Permissions +slug: androids-permissions +url: /blog/androids-permissions/ +original_url: https://www.codenameone.com/blog/androids-permissions.html +aliases: +- /blog/androids-permissions.html +date: '2014-03-23' +author: Shai Almog +--- + +![Header Image](/blog/androids-permissions/androids-permissions-1.jpg) + + + + + +![Picture](/blog/androids-permissions/androids-permissions-1.jpg) + + + + +One of the annoying tasks when programming native Android applications is tuning all the required permissions to match your codes requirements, when we started Codename One we aimed to simplify this. Our build server automatically introspects the classes you sent as part of the build and injects the right set of permissions required by your app. + +However, sometimes you might find the permissions that come up a bit confusing and might not understand why a specific permission came up. This maps Android permissions to the methods/classes in Codename One that would trigger them: + +android.permission.WRITE_EXTERNAL_STORAGE – this permission appears by default for Codename One applications, since the File API which is used extensively relies on it. You can explicitly disable it using the build argument android.blockExternalStoragePermission=true, notice that this is something we don’t test and it might fail for you on the device. + +android.permission.INTERNET – this is a hardcoded permission in Codename One, the ability to connect to the network is coded into all Codename One applications. + +android.hardware.camera & android.permission.RECORD_AUDIO – are triggered by com.codename1.Capture + +android.permission.RECORD_AUDIO – is triggered by MediaManager.createMediaRecorder() & Display.createMediaRecorder() + +android.permission.READ_PHONE_STATE – is triggered by com.codename1.ads package, com.codename1.components.Ads, com.codename1.components.ShareButton, com.codename1.media, com.codename1.push, Display.getUdid() & Display.getMsisdn(). This permission is required for media in order to suspend audio playback when you get a phone call. + +android.hardware.location, android.hardware.location.gps, android.permission.ACCESS_FINE_LOCATION, android.permission.ACCESS_MOCK_LOCATION & android.permission.ACCESS_COARSE_LOCATION – map to com.codename1.maps & com.codename1.location. + +package.permission.C2D_MESSAGE, com.google.android.c2dm.permission.RECEIVE, android.permission.RECEIVE_BOOT_COMPLETED – are requested by the com.codename1.push package + +android.permission.READ_CONTACTS – triggers by the package com.codename1.contacts & Display.getAllContacts(). + +android.permission.VIBRATE – is triggered by Display.vibrate() and Display.notifyStatusBar() + +android.permission.SEND_SMS – is triggered by Display.sendSMS() + +android.permission.WAKE_LOCK – is triggered by Display.lockScreen() & Display.setScreenSaverEnabled() + +android.permission.WRITE_CONTACTS – is triggered by Display.createContact(), Display.deleteContact(), ContactsManager.createContact() & ContactsManager. + +deleteContact() + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/animated-gif-support.md b/docs/website/content/blog/animated-gif-support.md new file mode 100644 index 0000000000..66f6f0ac04 --- /dev/null +++ b/docs/website/content/blog/animated-gif-support.md @@ -0,0 +1,129 @@ +--- +title: Animated Gif Support +slug: animated-gif-support +url: /blog/animated-gif-support/ +original_url: https://www.codenameone.com/blog/animated-gif-support.html +aliases: +- /blog/animated-gif-support.html +date: '2017-08-07' +author: Shai Almog +--- + +![Header Image](/blog/animated-gif-support/vacation.jpg) + +So you know how you write a blog post just before you go on vacation, press publish and never check that it actually got published…​ Funny thing, that’s exactly what I did and the blog post mentioning that I was on “vacation” for a couple of weeks never got published. Anyway, other people have been busy while I was “away” but I got a couple of things done too including animated gif support. + +Before we get to that Steve did a lot of work on Mac retina display support. This is a HUGE leap in usability if you use a retina Mac. It makes the iPhone 3gs skin tiny but you can now use the iPhone 5 skin without scaling…​ It looks great and uses the pixels on these Macs really well. + +I also released a new [cn1lib that implements animated GIF support](https://github.com/codenameone/AnimatedGifSupport/) in Codename One without the resource file hack. It’s still not something I would recommend as animated gifs can be pretty expensive in terms of resources but you can still use it to get a pretty decent animation. + +One of the cool things is that this works as a plug in image and you should be able to use it in most places where image works. There are caveats though. E.g. you can’t use it as a native map marker as that image is passed to native. But other than such API’s it should work in labels and even in background image styles, although I would suggest avoiding the latter as it would be a memory/battery drain. + +The library is in the extensions section and you can use it like this: + + + Form hi = new Form("Gif", new BorderLayout()); + + try { + hi.add(CENTER, new ScaleImageLabel(GifImage.decode(getResourceAsStream("/giphy-downsized.gif"), 1177720))); + } catch(IOException err) { + log(err); + } + hi.show(); + +Notice the following: + + * `GifImage.decode` can throw an `IOException` + + * It accepts an `InputStream` and the length of the input stream so you need to know the size in advance + + * It returns a `GifImage` which is a subclass of `Image` +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **salah Alhaddabi** — August 10, 2017 at 1:01 pm ([permalink](https://www.codenameone.com/blog/animated-gif-support.html#comment-23745)) + +> salah Alhaddabi says: +> +> Thanks a lot Shai. +> +> So does this mean that the image will be animated continously?? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanimated-gif-support.html) + + +### **Shai Almog** — August 11, 2017 at 7:22 am ([permalink](https://www.codenameone.com/blog/animated-gif-support.html#comment-23653)) + +> Shai Almog says: +> +> It will loop based on the loop settings in the GIF itself. GIF’s contain a loop count. If it’s 0 it means looping forever. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanimated-gif-support.html) + + +### **Francesco Galgani** — August 16, 2017 at 5:19 pm ([permalink](https://www.codenameone.com/blog/animated-gif-support.html#comment-23444)) + +> Francesco Galgani says: +> +> Thank you 🙂 +> How are the various densities managed by animated GIFs? Is there any multi-image equivalent for GIF? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanimated-gif-support.html) + + +### **Shai Almog** — August 17, 2017 at 4:39 am ([permalink](https://www.codenameone.com/blog/animated-gif-support.html#comment-24151)) + +> Shai Almog says: +> +> We don’t. GIF has no density support so it can only be scaled. Using an approach like multi-image with GIF would be prohibitive as the file size will balloon. GIF’s are huge enough as it is. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanimated-gif-support.html) + + +### **Francesco Galgani** — August 17, 2017 at 9:39 am ([permalink](https://www.codenameone.com/blog/animated-gif-support.html#comment-23637)) + +> Francesco Galgani says: +> +> Mmm… is there any way to get the right animated GIF size using an external service such as Cloudinary? I’ve never used it, so I don’t know if it supports animated GIFs. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanimated-gif-support.html) + + +### **Shai Almog** — August 18, 2017 at 5:56 am ([permalink](https://www.codenameone.com/blog/animated-gif-support.html#comment-23418)) + +> Shai Almog says: +> +> I don’t know. I’m not familiar with that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanimated-gif-support.html) + + +### **Rainer** — August 23, 2017 at 7:52 pm ([permalink](https://www.codenameone.com/blog/animated-gif-support.html#comment-24219)) + +> Rainer says: +> +> Hello! I tried the sample code with an animated gif, but nothing appears with the simulator +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanimated-gif-support.html) + + +### **Shai Almog** — August 24, 2017 at 9:04 am ([permalink](https://www.codenameone.com/blog/animated-gif-support.html#comment-23695)) + +> Shai Almog says: +> +> Do you see any error in the console? +> Have you tried with a different gif file? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fanimated-gif-support.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/announcing-coderad-2-0-preview.md b/docs/website/content/blog/announcing-coderad-2-0-preview.md new file mode 100644 index 0000000000..2c61acb3fa --- /dev/null +++ b/docs/website/content/blog/announcing-coderad-2-0-preview.md @@ -0,0 +1,182 @@ +--- +title: Announcing CodeRAD 2.0 Preview +slug: announcing-coderad-2-0-preview +url: /blog/announcing-coderad-2-0-preview/ +original_url: https://www.codenameone.com/blog/announcing-coderad-2-0-preview.html +aliases: +- /blog/announcing-coderad-2-0-preview.html +date: '2021-08-13' +author: Steve Hannah +description: We are proud to announce the immediate availability of the CodeRAD 2.0 + developer preview. CodeRAD is a modern MVC framework for building truly native, + mobile-first, pixel-perfect applications in Java and Kotlin. +--- + +We are proud to announce the immediate availability of the CodeRAD 2.0 developer preview. CodeRAD is a modern MVC framework for building truly native, mobile-first, pixel-perfect applications in Java and Kotlin. + +![CodeRAD 2.0](/blog/announcing-coderad-2-0-preview/CodeRAD-2.0-1024x576.jpg) + +CodeRAD 2 builds upon the solid foundation of CodeRAD 1.0, and adds several new features aimed at increasing component reuse, and improving developer experience. + +### Declarative View Syntax + +First among the long list of new features included in CodeRAD 2 is the ability to write your **View** classes in XML. + +For example, consider this simple login form component written in Java: + +```java + + package com.example.mybareapp; + +import com.codename1.ui.*; +import com.codename1.ui.layouts.BoxLayout; +import com.codename1.ui.layouts.FlowLayout; + +public class LoginForm extends Container { + public MyJavaForm() { + super(BoxLayout.y()); + + Label loginHeading = new Label("Login"); + loginHeading.setUIID("LoginHeading"); + + TextField username = new TextField(); + username.setMaxSize(30); + username.setConstraint(TextField.USERNAME); + username.setUIID("LoginField"); + username.setHint("Enter username"); + username.getHintLabel().setUIID("LoginFieldHint"); + + TextField password = new TextField(); + password.setConstraint(TextField.PASSWORD); + password.setUIID("LoginField"); + password.setHint("Enter password"); + password.getHintLabel().setUIID("LoginFieldHint"); + + Label usernameLabel = new Label("Username:"); + usernameLabel.setUIID("LoginFieldLabel"); + + Label passwordLabel = new Label("Password:"); + passwordLabel.setUIID("LoginFieldLabel"); + + Button login = new Button("Login"); + login.setUIID("LoginButton"); + + Button reset = new Button("Reset"); + reset.setUIID("ResetButton"); + + Container buttons = FlowLayout.encloseCenter( + reset, + login + ); + + addAll(loginHeading, + usernameLabel, + username, + passwordLabel, + password, + buttons + ); + } +} + + +``` + +You could write the same component as a CodeRAD view using the following: + +```xml + + xml version=1.0" ? + + Login + + Username: + + + Password: + + + + Reset + Login + + + + +``` + +The XML view is automatically transformed into a Java class by the CodeRAD annotation processor so that performance is on par with the hand-coded **Java** version. + + +This example demonstrates the primary benefit of using XML as a language for writing view classes: It is **declarative**! The XML representation maps directly to way the view will be presented in the app. + + +This example is just the tip of the iceberg, however, as CodeRAD’s XML views also include many other features aimed at making your development experience as smooth as possible. They have built-in support for property binding, for example, making it easy to maintain a clean separation between your **View** and **Controller** logic. + +### Hot Reload + +When building user interfaces, the biggest pain point, by far, is the “test-edit-reload” cycle. e.g. Load app in simulator, add label to your form, reload app in simulator, navigate back to form, repeat…​ + +Having to wait while the app is recompiled, and the simulator is reloaded each time you make a change is an excruciating productivity killer. + +CodeRAD 2 takes a giant step toward alleviating this problem with its introduction of **Hot Reload**. When this feature is enabled, the simulator will update in near real time (1-2 second delay) as you make changes to your application source. + +There are two modes for Hot Reload: + + +1. ****Reload Simulator**** – This will restart your app at your “start form” when changes are detected. + + +2. ****Reload Current Form**** – This will restart your app, and automatically load the current Form, to save you from having to manually navigate there. + +![codename-one-coderad-hot-reload-menu](/blog/announcing-coderad-2-0-preview/codename-one-coderad-hot-reload-menu.png) + +## Note + +> This is actually a pseudo "hot" reload, as it restarts your app rather than just patching code in place like the existing "Apply code changes" feature in most Java IDEs does. The "apply code changes" feature is very limited as it doesn’t apply to code that has already been run in your app, and it doesn’t support things like adding methods or classes. If you are trying to test changes to a UI form using "apply code changes", you would typically need to navigate away from your form, and navigate back after code changes are applied to see the changes. And this would still be insufficient in cases where the UI depends on "bootstrap" code in the app. A full app restart is necessary to reliably see the result of code changes, and this is what CodeRAD’s hot reload feature provides. + +### CodeRAD 2 Intro Video + +This introduction to CodeRAD 2 video is a good starting point if you want to learn more about the features and concepts of CodeRAD. + +### Getting Started + +We have added a “CodeRAD (MVC) Starter Project” option to the [Codename One initializr](https://start.codenameone.com/), which will give you a starting point for developing apps with CodeRAD 2. + +![](/blog/announcing-coderad-2-0-preview/initializr-rad-mvc-dropdown.png) + +The "Tweet App" template is also a CodeRAD 2 project that provides a twitter-style app template, with login forms, and a tweet list view. + +### Learn More + +We have developed a wealth of resources to help you get started with CodeRAD. After watching the [intro Video](https://youtu.be/x7qaWBTjwMI), you can check out these other resources: + +[The CodeRAD Developers Guide](https://shannah.github.io/CodeRAD/manual/) +: This includes an introduction to the key concepts, as well as two tutorials: + + ****1. [Getting Started](https://shannah.github.io/CodeRAD/manual/#getting-started)**** and [companion screencast](https://youtu.be/QdyO4tpYOHs). + + ****2. [Building a Twitter Clone](https://shannah.github.io/CodeRAD/manual/#_app_example_1_a_twitter_clone)**** + +****[The CodeRAD Wiki](https://github.com/shannah/CodeRAD/wiki)**** +: The best source for reference documentation on CodeRAD components. + +****[The CodeRAD Javadocs](https://shannah.github.io/CodeRAD/javadoc)**** +: JavaDocs for CodeRAD. + +****[Github Repository](https://github.com/shannah/CodeRAD)**** +: All the source for CodeRAD. + +## Sample Projects + +****1. [CodeRAD2 Samples](https://github.com/shannah/coderad2-samples)**** – Includes a growing set of samples demonstrating the use of CodeRAD components. **Views are located in the [src/main/rad/views directory](https://github.com/shannah/coderad2-samples/tree/master/common/src/main/rad/views/com/codename1/rad/sampler).** + +****2. [Tweet App](https://github.com/shannah/tweetapp)**** – A partial twitter clone. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/around.md b/docs/website/content/blog/around.md new file mode 100644 index 0000000000..e70610337b --- /dev/null +++ b/docs/website/content/blog/around.md @@ -0,0 +1,94 @@ +--- +title: Around +slug: around +url: /blog/around/ +original_url: https://www.codenameone.com/blog/around.html +aliases: +- /blog/around.html +date: '2016-03-28' +author: Shai Almog +--- + +![Header Image](/blog/around/circle-progress-blog-post.png) + +Chen just released a [new cn1lib](https://github.com/chen-fishbein/CN1CircleProgress) for circular progress indicators +of various types. This is an often requested feature and there were many ways to implement this in the past +but it is now far easier to do this with shape clipping. + +You can use the circular progress API using code such as: + + + Form hi = new Form("Circle Progress"); + hi.setLayout(new BoxLayout(BoxLayout.Y_AXIS)); + final CircleProgress p = new CircleProgress(); + p.setProgress(100); + p.setClockwise(true); + p.setStartAngle(CircleProgress.START_9_OCLOCK); + hi.add(p); + + final ArcProgress p2 = new ArcProgress(); + p2.setProgress(70); + hi.add(p2); + + final CircleFilledProgress p3 = new CircleFilledProgress(); + p3.setProgress(70); + hi.add(p3); + + Slider slider = new Slider(); + slider.setEditable(true); + slider.addDataChangedListener(new DataChangedListener() { + + @Override + public void dataChanged(int type, int index) { + p.setProgress(index); + p2.setProgress(index); + p3.setProgress(index); + } + }); + hi.add(slider); + + hi.show(); + +Which results in this: + +![Circle progress indicators in action](/blog/around/circle-progress.png) + +Figure 1. Circle progress indicators in action + +### IntelliJ/IDEA Rewrite + +This has been a very slow news week due to many reasons but a big chunk of that is our focus on some big +tasks. + +I’m working on a complete rewrite of the IntelliJ/IDEA plugin, I hope to have it out next week. This +should bring IntelliJ/IDEA into par with the rest of the IDE’s and in my humble opinion it might leapfrog other IDE +plugins. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Msizi** — March 31, 2016 at 5:06 pm ([permalink](https://www.codenameone.com/blog/around.html#comment-22728)) + +> Great work!!!! just a question, how to change the color of the circle. instead of blue maybe use red or any different color +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faround.html) + + +### **Chen Fishbein** — April 1, 2016 at 6:38 am ([permalink](https://www.codenameone.com/blog/around.html#comment-22460)) + +> Chen Fishbein says: +> +> Thanks, the colors are coming from the “Slider” theme entry, just modify the Slider colors on the theme to change the colors +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Faround.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows.md b/docs/website/content/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows.md new file mode 100644 index 0000000000..2080a6ffa2 --- /dev/null +++ b/docs/website/content/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows.md @@ -0,0 +1,319 @@ +--- +title: Associating Your App with File Extension/Mime Type on iPhone (iOS), Android + & Windows +slug: associating-your-app-with-file-extension-mime-types-iphone-android-windows +url: /blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/ +original_url: https://www.codenameone.com/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows.html +aliases: +- /blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows.html +date: '2016-11-07' +author: Steve Hannah +--- + +![Header Image](/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/file-type-associations.jpg) + +One of the compelling reasons to go native (vs say a web app) is to better integrate with the platform. One form of integration that is frequently handy is the ability register your app to handle certain file types so that it is listed as one of the options when a user tries to view a file of that type. Codename One supports this use case via the “AppArg” display property – the same, simple mechanism used for handling custom link types in your app. + +With the “Meme Maker” demo that I just created, I wanted users to be able to select a photo from another app (like Photos on Android), and send it directly to the Meme Maker app as the basis for creating a Meme. + +In case you’re not familiar with “Memes”, they are those sometimes annoying photos that litter your facebook feed with witty captions laid over them. E.g: + +![Example cat meme](/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/example-cat-meme.jpg) + +Figure 1. Example cat meme + +Meme Maker is a very simple app. It allows the user to select a photo, and it provides some text laid over the photo which the user can edit. When the meme is finished, it can be exported as an image, and/or shared to Facebook or other social media. + +All this is simple to do in Codename One. Selecting an image, can be achieved using `Display.openGallery()`, which allows the user to choose from one of the images in their device’s photos. Sharing an image can be achieved via `Display.execute()` or with the `ShareButton` component. + +I wanted to go a step further, though, so that users could launch MemeMaker directly from their Photos app. For a simple app like this, allowing the user to “Share” an image **to** the app can significantly improve the user experience. + +### How to Register an App to open a File Type + +Registering your app to open a a file type involves two parts: + + 1. Add some build hints to inject the appropriate metadata into each native platform config files (e.g. The info.plist on iOS, the manifest file on Android, etc..) to inform the native platform that the app can open the specified file types. + + 2. Check for `Display.getInstance().getProperty("AppArg", null)` at the beginning of your app’s `start()` method to see if the app was opened as a result of file being opened or shared. If present, it will be the path to a file that you can access using `FileSystemStorage`. + +### An example from the “Meme Maker” demo + +Lets’ start by looking at the code that handles the “AppArg”. At the beginning of the `start()` method we have: + + + Display disp = Display.getInstance(); + String arg = disp.getProperty("AppArg", null); + if (arg != null) { + disp.setProperty("AppArg", null); + disp.callSerially(()->{ + fireImageSelected(arg); + }); + } + +So, what we’ve done here is + + 1. Check the “AppArg” property. + + 1. If it is not null, we set it null (just so we don’t mistake it being set in future starts). + + 2. I use `callSerially()` to defer the actual selection of the image until after the rest of the `start()` method has run. That is app-specific, and not necessary in general for processing app arguments. + +That’s all there is to it. + +Now the app is equipped to “handle” files that are passed to it on startup. However we still need to register the app with each platform so that the operating system knows to make our app available as a share target (or an “open with” target). + +### Android-Specific Configuration + +There are two build-hints related to Android that we will need to employ: + + 1. `android.activity.launchMode=singleTask`. + +The default launch mode for Codename One apps is “singleTop”. Unfortunately this doesn’t really work very well if the app can be launched from other apps to open files. I won’t go into specifics here about the differences between “singleTop” and “singleTask” launch mode. Just know that if you want your app to work properly as a share target, you need to set this build hint to “singleTask”. + +You can read more about Android’s `activity:launchMode` directive [here](https://developer.android.com/guide/topics/manifest/activity-element.html). + + 2. `android.xintent_filter` + +This is where we add the `` tags to be injected into the app’s manifest file. These filters will register our app to open specific file types. The value I used for **Meme Maker** is: + + + + + + + + + + + + +The first filter says that the app is an eligible “share” target for files with mimetype “image/**“. The second says that the app is eligible to “Open” files with mimetype “image/** “. Each is used in different instances. A simple way to think of this is, from a Codename One’s app perspective: + + 1. `Display.execute(filepath)` – will allow the user to “open” the file using apps that have registered an appropriate intent filter with action `android.intent.action.VIEW`. + + 2. `Display.share(null, filepath, "image/png")` – will allow the user to “send” the file to an app that has registered an appropriate intent filter with action `android.intent.action.SEND`. + +Here are some sceen-shots of how the integration looks on my Nexus 5. + +I did a search on Google for “blank meme photos”. Once I found a photo, I did a long-press on the image (in Chrome), to open the context menu: + +![Android chrome context menu](/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/android-chrome-context-menu.png) + +Figure 2. Android chrome context menu + +Then when I tap on “Share”, it gives me a list of the apps that I can share this image to. MemeMaker is listed there: + +![Share image to meme maker](/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/android-chrome-sharing-menu.png) + +Figure 3. Share image to meme maker + +Then it opens Meme Maker with the image already loaded into the background: + +![Meme maker with preloaded image](/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/android-mememaker-fistpump.png) + +Figure 4. Meme maker with preloaded image + +### iOS-Specific Configuration + +On iOS, we only need concern ourselves with one build hint: + +`ios.plistInject` + +The content I used for the Meme Maker app is: + + + CFBundleDocumentTypes + + + CFBundleTypeName + image + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + LSItemContentTypes + + public.image + + + + +Don’t be intimidated by this snippet. There’s a lot there, but for the most part it is just boiler-plate copy and paste. Here is a break-down of the values and their meaning: + + 1. `CFBundleTypeName` – A name for this bundle type. You can provide pretty much any value you want here. I used “image”, but it could have been “foo” or “bar”. + + 2. `CFBundleTypeRole` – The role of this app. In our case I’m just registering it as an image viewer. The value can be Editor, Viewer, Shell, or None. This key is required. + + 3. `LSHandlerRank` – How iOS ranks the relevance against other apps that open this file type. Possible values: “Owner”, “Alternate”, “Default”, “None” + + 4. `LSItemContentTypes` – A list of the content types that are being registered to be opened by the app. iOS uses UTIs instead of mimetypes here. The `public.image` UTI is basically the same as the `image/*` mimetype. You can see a list of all public UTIs [here](https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html). + +__ | iOS has (at least) two different mechanisms for handling file types in your app. The above `ios.plistInject` value will register the app to be able to “Open” an image file, but it won’t allow it to receive it as a share target. The distinction is subtle and it depends on what mechanism is used to launch the “Open with” or “Share” dialog in the source app. E.g. If you view a PDF inside Safari, it will provide an “Open with…​” (label changed to “More…​” in iOS 10) link in the top left, which, if tapped, will provide the user with a list of registered apps that can open a PDF. If our app was registered to open a PDF in the same way that it is registered to open images, then our app would appear in this list of elligible apps. +---|--- + +However, there is also a “Share” button at the bottom of the screen in Safari. This won’t include our app as it uses a different mechanism for registering apps. Registration to appear in this menu is more complicated and beyond the scope of this post. + +Unfortunately I couldn’t find an example in the latest OS where an app provides “Open with” an image. It seems that things are shifting towards “sharing” when images are involved, and as I mentioned above, this is a little more complex. However, for other files types, like PDF, the “open with” workflow is still common. For example, here is a sample of a PDF as viewed in iOS’ Safari. If I tap on the PDF, it provides a little menu along the top with a “More…​” option, as shown here: + +![iOS Open with menu bar](/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/ios-pdf-open-with.png) + +And when I tap on “More…​” I see: + +![iOS Open with dialog](/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/ios-open-with-dialog-ocr.png) + +Figure 5. iOS Open with dialog + +The first application listed here is “OCR.net”, which is an app that I developed using Codename One. It includes the following `ios.plistInject` directive to be shown here: + + + CFBundleDocumentTypes + + + CFBundleTypeName + pdf + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + LSItemContentTypes + + com.adobe.pdf + + + + CFBundleTypeName + image + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + LSItemContentTypes + + public.image + + + + +### Windows-Specific Configuration + +The process for UWP is similar to both iOS and Android. In this case we use the `windows.extensions` directive to inject content into the windows manifest file. In this case, we use: + + + + + imagesicon.png + + .jpg + .jpeg + .gif + .png + + + + +With this build hint, our app is registered to open files with .jpg, jpeg, .gif, and .png files. On the desktop, this means you can right click on files of these types, select “Open with” in the contextual menu, and then select “Meme maker” as shown here: + +![Windows 10 open with option](/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/uwp-open-with.png) + +For more information about the available options in UWP, see [handling file activation](https://msdn.microsoft.com/en-us/windows/uwp/launch-resume/handle-file-activation) on MSDN. + +#### Windows 10 Share Targets + +As with iOS and Android, Windows 10 treats “share targets” slightly differently than file associations. The `FileTypeAssociation` tag registers the app to be able to “open” files of the specified types, but it doesn’t register to be a share target. Share targets are those apps that appear in the sharing dialog when a users chooses “Share” from a context menu. E.g. When I right click on this image in Edge, it gives me an option to “Share” the image: + +![Windows 10 share picture](/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/windows-10-share-picture.png) + +On the desktop, this will open a sidebar with a list of applications to which this image can be shared: + +![Windows 10 share sidebar](/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/windows-10-share-sidebar.png) + +In the above screenshot, notice that Meme Maker is listed as one of the apps. This version of MemeMaker was built using an some additional options in the `windows.extensions` build hint: + + + + + + .jpg + .gif + .png + .jpeg + + StorageItems + + + +__ | For more information about the “windows.shareTarget” category, see [Microsoft’s docs](https://msdn.microsoft.com/en-us/library/windows/apps/br211466.aspx) on the subject. +---|--- + +With this share target information, the app was listed in the Sharing sidebar when an image file was shared by another app. Selecting “Meme maker” in this sidebar would open Mememaker inside the sharing sidebar as shown here: + +![Meme maker loaded inside Windows 10 sidebar](/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows/meme-maker-in-uwp-sharing-sidebar.png) + +Figure 6. Meme maker loaded inside Windows 10 sidebar + +__ | Ultimately I opted not to include the “shareTarget” functionality in the finished app because it resulted in some peculiar behaviour when the app was opened in both the sharing sidebar and as a stand-alone app. +---|--- + +### Get the Meme Maker App + + 1. [On the Play Store](https://play.google.com/store/apps/details?id=com.codename1.demos.mememaker) + + 2. [In the Windows Store](https://www.microsoft.com/en-us/store/p/codename-one-meme-maker/9nblggh441nf) + + 3. [In the iTunes Store](https://itunes.apple.com/us/app/codename-one-meme-maker/id1171538632) + + 4. [On GitHub](https://github.com/shannah/mememaker) +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Carlos** — November 8, 2016 at 4:03 pm ([permalink](https://www.codenameone.com/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows.html#comment-23053)) + +> Excelent. +> +> One big step forward would be to read Exif rotation and correct the image accordingly, as this is something that happens very often. Most devices don’t actually rotate pictures, but mark them as such in the exif data. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fassociating-your-app-with-file-extension-mime-types-iphone-android-windows.html) + + +### **bryan** — November 8, 2016 at 7:37 pm ([permalink](https://www.codenameone.com/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows.html#comment-22806)) + +> Great tutorial Steve – thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fassociating-your-app-with-file-extension-mime-types-iphone-android-windows.html) + + +### **Shai Almog** — November 9, 2016 at 7:31 am ([permalink](https://www.codenameone.com/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows.html#comment-23043)) + +> Thanks. +> +> AFAIK we already do that implicitly in our capture implementation. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fassociating-your-app-with-file-extension-mime-types-iphone-android-windows.html) + + +### **Carlos** — November 9, 2016 at 9:09 am ([permalink](https://www.codenameone.com/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows.html#comment-23085)) + +> This is what I get in what should be a vertical pic… +> +> [https://uploads.disquscdn.c…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fassociating-your-app-with-file-extension-mime-types-iphone-android-windows.html) + + +### **Shai Almog** — November 10, 2016 at 4:57 am ([permalink](https://www.codenameone.com/blog/associating-your-app-with-file-extension-mime-types-iphone-android-windows.html#comment-22989)) + +> Looking at the code it seems to no longer be there, not sure why. I’ll have to ask on that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fassociating-your-app-with-file-extension-mime-types-iphone-android-windows.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/async-debugging-with-intellij-idea.md b/docs/website/content/blog/async-debugging-with-intellij-idea.md new file mode 100644 index 0000000000..5cf7a2302d --- /dev/null +++ b/docs/website/content/blog/async-debugging-with-intellij-idea.md @@ -0,0 +1,152 @@ +--- +title: Async Debugging with IntelliJ IDEA +slug: async-debugging-with-intellij-idea +url: /blog/async-debugging-with-intellij-idea/ +original_url: https://www.codenameone.com/blog/async-debugging-with-intellij-idea.html +aliases: +- /blog/async-debugging-with-intellij-idea.html +date: '2022-04-11' +author: Steve Hannah +description: We have added support for IntelliJ’s asynchronous code debugging feature, + so that you can more easily debug your asynchronous code. +--- + +We have added support for IntelliJ’s asynchronous code debugging feature, so that you can more easily debug your asynchronous code. + +![Async Debugging with IntelliJ IDEA - Codename One](/blog/async-debugging-with-intellij-idea/Async-Debugging-with-IntelliJ-IDEA-Codename-One-1024x536.jpg) + +When debugging your apps in IntelliJ, stack-traces will include the “async” context’s stack frames so that you can see the stack trace of the code that scheduled your asynchronous code. For example, methods like `callSerially()` are notoriously prickly to debug because the “logical” stack trace includes the stack frame in which `callSerially(Runnable)` is called, and also the frame in which the **Runnable**‘s `run()` method is called. It is very difficult to walk up this “logical” stack from a break-point inside the `run()` method. + +To demonstrate this point, consider the following code: + +```java + + package com.codenameone.devmode; + +import com.codename1.ui.Button; +import com.codename1.ui.Form; +import com.codename1.ui.events.ActionEvent; +import com.codename1.ui.layouts.BorderLayout; + +import static com.codename1.ui.CN.callSerially; + +public class TestAsyncDebugForm extends Form { + + public TestAsyncDebugForm() { + super(new BorderLayout(BorderLayout.CENTER_BEHAVIOR_CENTER_ABSOLUTE)); + Button btn = new Button("Hello 1"); + btn.addActionListener(this::button1Clicked); + Button btn2 = new Button("Hello 2"); + btn2.addActionListener(this::button2Clicked); + add(BorderLayout.CENTER, btn); + add(BorderLayout.SOUTH, btn2); + } + + private void button1Clicked(ActionEvent evt) { + callSerially(printHello); + } + + private void button2Clicked(ActionEvent evt) { + callSerially(printHello); + } + + Runnable printHello = () -> { + printHello(); + }; + + private void printHello() { + System.out.println("Hello"); + } +} + + +``` + +This creates a form with two buttons: “Hello 1” and “Hello 2”. Clicking on either button will ultimately trigger an async call to the `printHello()` method, but they follow different code paths to get there. Clicking “Hello 1” triggers the `button1Clicked()` method, and clicking “Hello 2” triggers the `button2Clicked()` method – both triggering an async call to `printHello()`. + +Let’s set a break point inside the `printHello()` method: + +![](/blog/async-debugging-with-intellij-idea/break-point-hello.png) + +If we debug the app and press “Hello 1”, we will see a stack trace like the following: + +![](/blog/async-debugging-with-intellij-idea/stack-trace-hello1-sync.png) + +There is no way to tell from this stack trace which button was pressed to trigger it. If we walk up the stack we hit a dead end at **executeSerialCall()**. This is because the break-point occurs in the asynchronous callback of `callSerially()`, so the original stack frame for the call to `callSerially()` is already “gone” by the time we hit our break-point. + +Now, let’s try this again with async debugging enabled. The stack trace this time will look like: + +![](/blog/async-debugging-with-intellij-idea/stack-trace-hello1-async.png) + +We can now trace this break-point back to “Button 1” definitively because it displays both the “execution” stack frame’s trace, and the scheduler’s stack frame’s trace. + +### Enabling Async Debugging + +Async debugging requires: + + +1. That you are using IntelliJ IDEA + + +2. That your project is using Maven + + +3. That your `cn1.version` property is set to 7.0.65 or higher. + + +4. That your project is configured to use the `com.codename1.annotations.Async` annotations for the async stack traces feature. All projects created using the [Codename One initializr](https://start.codenameone.com/) after April 18th will include this configuration “out of the box”, so it should “just work”. + +### Configuring the Async Annotations + +As mentioned above, new projects created with [Codename One initializr](https://start.codenameone.com/) after April 18th, should include async stack traces out of the box. If you have an existing project on which you want to enable async traces, you just need to tell IntelliJ to use the Codename One annotations for async stack traces. The easiest way is to simply copy the [debugger.xml](https://github.com/shannah/cn1-maven-archetypes/blob/master/cn1app-archetype/src/main/resources/archetype-resources/.idea/debugger.xml) file from the cn1app-archetype into the `.idea` directory of your project. + +## Place the following into the .idea/debugger.xml file of your project to enable async stack-traces. + +```xml + + xml version="1.0" encoding="UTF-8"? + + + + + + + + + + + + +``` + +Alternatively you can follow the IntelliJ documentation for configuring custom annotations [here](https://www.jetbrains.com/help/idea/debug-asynchronous-code.html#custom_async_annotations). You should add `com.codename1.annotations.Async.Schedule` to the list of Async Schedule annotations, and `com.codename1.annotations.Async.Execute` to the list of Async Execute annotations. The configuration dialog is shown below. + +![](/blog/async-debugging-with-intellij-idea/configure-annotations.png) + +Figure 1. The Async Annotations configuration dialog in IntelliJ. + +### For More Information + +For more information about IntelliJ’s asynchronous debugging feature, see [the IntelliJ documentation on the subject](https://www.jetbrains.com/help/idea/debug-asynchronous-code.html). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved here for historical context. New discussion happens in the Discussion section below._ + + +### **Antonio Rios** — April 14, 2022 at 3:20 am ([permalink](https://www.codenameone.com/blog/async-debugging-with-intellij-idea.html#comment-24534)) + +> Antonio Rios says: +> +> Wonderful new features! Great job guys! I’m literally impress every time I visit the blog and see some new cool feature added. Keep those cool useful features coming please. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fasync-debugging-with-intellij-idea.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/asynchronous-media.md b/docs/website/content/blog/asynchronous-media.md new file mode 100644 index 0000000000..84c58e8d0f --- /dev/null +++ b/docs/website/content/blog/asynchronous-media.md @@ -0,0 +1,52 @@ +--- +title: Asynchronous Media +slug: asynchronous-media +url: /blog/asynchronous-media/ +original_url: https://www.codenameone.com/blog/asynchronous-media.html +aliases: +- /blog/asynchronous-media.html +date: '2019-05-22' +author: Shai Almog +--- + +![Header Image](/blog/asynchronous-media/new-features-3.jpg) + +There are a lot of fixes and new features that I don’t get to cover enough as I’ve been busy on several fronts. One of the new features is support for asynchronous media API’s. These let us create a media object without waiting for it to complete. This is very useful if you have a complex UI and want to play a media file while doing other things. + +E.g. if you’re scrolling in a social network feed and want to play a media preview. You might create a media object but don’t want it to block the current call. You can do this using code such as: + + + AsyncResource async = Display.getInstance().createMediaAsync(URL_TO_MEDIA, isVideo, null); + async.ready(mediaInstance -> playMedia(mediaInstance)); + +You will notice the usage of `AsyncResource` which is similar to a future or a promise in other platforms. It lets you monitor the status of an asynchronous approach. This block would execute quickly but the `playMedia` call would happen when loading is completed. + +### Rendering Hints + +One of the API’s I dislike in JavaSE is the `Graphics2D` rendering hints. It’s a bit opaque in the choices it exposes. I want fast and good looking graphics but the tradeoff isn’t always clear. How much would I “pay” for good looking in this case in terms of speed and visa versa. + +Now we also have one rendering hint in our graphics: + + + graphics.setRenderingHints(Graphics.RENDERING_HINT_FAST); + +I’m not too crazy about the name as it’s a bit misleading. I’m sure developers would just turn it on to make everything “go fast” then complain when it has no impact…​ It doesn’t do that. + +Only iOS uses this and even then only when rendering images. Since copying images to textures is expensive, we keep the last generated texture cached. This works well if we are always rendering the image at the same size. If we are constantly rendering the same image at different sizes, then we’ll constantly be invalidating the cache, this results in artifacts. This affected pinch zoom in the image viewer [causing it to be choppy](https://github.com/codenameone/CodenameOne/issues/2786) as it had to regenerate a texture for every change in size. When Fast rendering is enabled, we now only invalidate the texture cache if the image is larger or smaller than the existing texture by more than a factor of 2. + +This change also fixed a bug that caused images to be rendered as black if they are larger than the max OGL texture size. Now it will cap the size of the texture at the max OGL size, and it will use the GPU to scale the texture to the desired size. + +### Uppercase + +`TextArea` now supports a new `UPPERCASE` constraint which lets you request uppercase input. Generally it will just popup the keyboard with the capslock on. You can use it as such: + + + textFieldOrArea.setConstrainer(TextArea.UPPERCASE); + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/attachments-network-speed-and-more.md b/docs/website/content/blog/attachments-network-speed-and-more.md new file mode 100644 index 0000000000..c0928bc1dd --- /dev/null +++ b/docs/website/content/blog/attachments-network-speed-and-more.md @@ -0,0 +1,43 @@ +--- +title: Attachments, Network Speed and More +slug: attachments-network-speed-and-more +url: /blog/attachments-network-speed-and-more/ +original_url: https://www.codenameone.com/blog/attachments-network-speed-and-more.html +aliases: +- /blog/attachments-network-speed-and-more.html +date: '2013-09-04' +author: Shai Almog +--- + +![Header Image](/blog/attachments-network-speed-and-more/attachments-network-speed-and-more-1.png) + + + + + +![Picture](/blog/attachments-network-speed-and-more/attachments-network-speed-and-more-1.png) + + + + +Our email api only supported a single attachment until now. We just added an api that allows for multiple attachments which we will add in the next update. Notice that multiple attachments will only work on iOS/Android at the moment. + + + +Also in this update you would find a fix for the Twitter service (see the TwitterRESTService class) and some other capabilities such as support for network performance issues. + + + +The simulator now allows you to simulate a case of no network connectivity and slow connectivity. This simulation isn’t accurate but it should help in gauging the feel for such cases and debugging complex scenarios. To see this in action just select the Network section in the simulator menu and select the mode for the simulator to run in. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/automatic-build-hints-configuration.md b/docs/website/content/blog/automatic-build-hints-configuration.md new file mode 100644 index 0000000000..86db44705a --- /dev/null +++ b/docs/website/content/blog/automatic-build-hints-configuration.md @@ -0,0 +1,53 @@ +--- +title: Automatic Build Hints Configuration +slug: automatic-build-hints-configuration +url: /blog/automatic-build-hints-configuration/ +original_url: https://www.codenameone.com/blog/automatic-build-hints-configuration.html +aliases: +- /blog/automatic-build-hints-configuration.html +date: '2017-01-17' +author: Shai Almog +--- + +![Header Image](/blog/automatic-build-hints-configuration/new-features-4.jpg) + +We try to make Codename One “seamless”, this expresses itself in many small details such as the automatic detection of permissions on Android etc. The build servers go a long way in setting up the environment as intuitive. But it’s not enough, build hints are often confusing and obscure. It’s just hard to abstract the mess that is native mobile OS’s and the odd policies from Apple/Google…​ + +E.g. a common problem developers face is location code that doesn’t work in iOS. This is due to the `ios.locationUsageDescription` build hint that’s required. The reason we added that build hint was a requirement by Apple to provide a description for every app that uses the location service. + +We could detect usage of the API in the servers and inject some random string into place and in fact that was what we were about to do with [issue 1415](https://github.com/codenameone/CodenameOne/issues/1415) but then it occurred to us that there is a much simpler way that will also provide far more power…​ + +We added two new API’s to `Display`: + + + /** + * Returns the build hints for the simulator, this will only work in the debug environment and it's + * designed to allow extensions/API's to verify user settings/build hints exist + * @return map of the build hints that isn't modified without the codename1.arg. prefix + */ + public Map getProjectBuildHints() {} + + /** + * Sets a build hint into the settings while overwriting any previous value. This will only work in the + * debug environment and it's designed to allow extensions/API's to verify user settings/build hints exist. + * Important: this will throw an exception outside of the simulator! + * @param key the build hint without the codename1.arg. prefix + * @param value the value for the hint + */ + public void setProjectBuildHint(String key, String value) {} + +Both of these allow us to detect if a build hint is set and if not (or if set incorrectly) set its value…​ + +So now if you will use the location API from the simulator and you didn’t define `ios.locationUsageDescription` we will implicitly define a string there. The cool thing is that you will now see that string in your settings and you would be able to customize it easily. + +However, this gets way better than just that trivial example! + +The real value is for 3rd party libraries, e.g. Google Maps or Parse. They can inspect the build hints in the simulator and show an error in case of a misconfiguration. They can even show a setup UI. Demos that need special keys in place can force the developer to set them up properly before continuing. We plan to make extensive use of this feature moving forward. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/automatic-caching.md b/docs/website/content/blog/automatic-caching.md new file mode 100644 index 0000000000..10239bd451 --- /dev/null +++ b/docs/website/content/blog/automatic-caching.md @@ -0,0 +1,79 @@ +--- +title: Automatic Caching +slug: automatic-caching +url: /blog/automatic-caching/ +original_url: https://www.codenameone.com/blog/automatic-caching.html +aliases: +- /blog/automatic-caching.html +date: '2016-12-14' +author: Shai Almog +--- + +![Header Image](/blog/automatic-caching/networking.jpg) + +Caching server data locally is a huge part of the advantage a native app has over a web app. Normally this is +non-trivial as it requires a delicate balance especially if you want to test the server resource for changes. + +HTTP provides two ways to do that the [ETag](https://en.wikipedia.org/wiki/HTTP_ETag) and +[Last-Modified](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified). While both are +great they are non-trivial to use and by no definition seamless. + +We just added an experimental feature to connection request that allows you to set the caching mode to one of +4 states either globally or per connection request: + + * **OFF** is the default meaning no caching. + + * **SMART** means all get requests are cached intelligently and caching is “mostly” seamless + + * **MANUAL** means that the developer is responsible for the actual caching but the system will not do a request on a resource that’s already “fresh” + + * **OFFLINE** will fetch data from the cache and wont try to go to the server. It will generate a 404 error if data isn’t available + +You can toggle these in the specific request by using `setCacheMode(CachingMode)` and set the global +default using `setDefaultCacheMode(CachingMode)`. + +__ | Caching only applies to `GET` operations, it will not work for `POST` or other methods +---|--- + +There are several methods of interest to keep an eye for: + + + protected InputStream getCachedData() throws IOException; + protected void cacheUnmodified() throws IOException; + public void purgeCache(); + public static void purgeCacheDirectory() throws IOException; + +### getCachedData() + +This returns the cached data. This is invoked to implement `readResponse(InputStream)` when running offline +or when we detect that the local cache isn’t stale. + +The smart mode implements this properly and will fetch the right data. However, the manual mode doesn’t +store the data and relies on you to do so. In that case you need to return the data you stored at this point and must +implement this method for manual mode. + +### cacheUnmodified() + +This is a callback that’s invoked to indicate a cache hit, meaning that we already have the data. + +The default implementation still tries to call all the pieces for compatibility (e.g. `readResponse`). +However, if this is unnecessary you can override that method with a custom implementation or even a blank +implementation to block such a case. + +### purgeCache & purgeCacheDirectory + +These methods are pretty self explanatory. Notice one caveat though…​ + +When you download a file or a storage element we don’t cache them and rely on the file/storage element to +be present and serve as “cache”. When purging we won’t delete a file or storage element you downloaded and +thus these might remain. + +However, we do remove the `ETag` and `Last-Modified` data so the files might get refreshed the next time around. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/automatically-install-update-distribute-cn1libs-extensions.md b/docs/website/content/blog/automatically-install-update-distribute-cn1libs-extensions.md new file mode 100644 index 0000000000..cf3f5dd433 --- /dev/null +++ b/docs/website/content/blog/automatically-install-update-distribute-cn1libs-extensions.md @@ -0,0 +1,220 @@ +--- +title: Automatically Install, Update & Distribute cn1libs (extensions) +slug: automatically-install-update-distribute-cn1libs-extensions +url: /blog/automatically-install-update-distribute-cn1libs-extensions/ +original_url: https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html +aliases: +- /blog/automatically-install-update-distribute-cn1libs-extensions.html +date: '2016-06-07' +author: Shai Almog +--- + +![Header Image](/blog/automatically-install-update-distribute-cn1libs-extensions/extensions.png) + +Managing your project dependencies and 3rd party extensions among the hard to navigate list of cn1libs has +always been challenging. We are now tackling this problem in the new settings UI which is scheduled to launch +for all IDE’s this Friday. + +To get started just open the new Codename One settings UI: + +![Launching the new preferences UI](/blog/automatically-install-update-distribute-cn1libs-extensions/newsettings-ui.png) + +Figure 1. Launching the new preferences UI + +__ | You need to use an up to date plugin from the June 10th release +---|--- + +Then open the extensions option: + +![Extensions Option In the Settings](/blog/automatically-install-update-distribute-cn1libs-extensions/extensions-section.png) + +Figure 2. Extensions Option In the Settings + +Once you launch the extensions UI you should see this screen where you can download/search thru available +Codename One extensions. + +![The Extensions UI](/blog/automatically-install-update-distribute-cn1libs-extensions/codenameone-extensions-ui.png) + +Figure 3. The Extensions UI + +Once downloaded you will see a check mark next to the installed extensions. + +### Adding your Own + +The list of extensions is based on a [github project](https://github.com/codenameone/CodenameOneLibs) which +you can fork to extend. You can update the version of cn1libs you make and also contribute. Notice that while +all the current libraries in the list are open source this is by no means a requirement…​ + +We have quite a few cn1libs already from the community and we’d appreciate more of those to help the community +at large. + +### What’s Next? + +We will probably refine this process as it matures e.g. add more tagging based UI and make an “uninstall” +process as well…​ + +However, this depends a lot on your involvement & feedback so let us know what you think and take part in the +project. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — June 8, 2016 at 2:50 pm ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-21512)) + +> This sounds really cool! I’m definitely gonna try it out in the upcoming parse4cn1 update scheduled for later this month and give you feedback. +> +> By the way, I have an interesting situation and I’d like to know how best to handle it. The current (and most likely upcoming) version(s) of parse4cn1 ships in two flavors: One with push notification support and one without, the reason being that push notification requires some native sdks which conflicted with those in CN1 causing build failures (e.g., Facebook SDK). +> How best can I handle this? Make two separate CN1libs (e.g. Parse4CN1.Push and Parse4CN1.NoPush)? Ideas are most welcome. +> +> Can’t wait to try this out 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Shai Almog** — June 9, 2016 at 3:50 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-22892)) + +> Thanks! +> +> We wanted the current version to be as simple as possible and the only complexity we really tried to solve was relatively simple dependency management. So I don’t see another way other than the one you suggested. +> +> FYI parse4cn1 is already in the current repository (we added most of our existing cn1libs section). At the moment we didn’t take that strategy and it’s listed as the standard cn1lib. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Chidiebere Okwudire** — June 9, 2016 at 7:47 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-22696)) + +> Yeah, I already peeped at the git repo. The version number is also incorrect but that’s no problem. I’ll fix it within the coming update hopefully next week. At the time, I’ll also split it up +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Shai Almog** — June 9, 2016 at 8:05 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-22810)) + +> Shai Almog says: +> +> Notice that this isn’t the “actual” version number. It’s the version in our repo which is an integer. We use this to determine if there is an update only and this isn’t displayed to the user… So the number is fine in that sense. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Chidiebere Okwudire** — June 17, 2016 at 8:30 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-22817)) + +> Chidiebere Okwudire says: +> +> Good point. By the way, do the IDEs automatically detect updates of the github repo is are the changes only available after the weekly cn1 updates? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Shai Almog** — June 17, 2016 at 11:51 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-22709)) + +> Shai Almog says: +> +> Neither. It’s a separate process where we manually deploy the changes to the [codenameone.com]() website. We try to be quick about it but there is also caching from CDN and it’s a manual thing. +> +> The logic is that we want the ability to migrate hosting. In the past we had an update center for NetBeans on Google code and it seems some people were still using it until now… In the future github might come down on partial binary hosting and we’d like such an eventuality to be seamless to our users. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Jérémy MARQUER** — August 9, 2016 at 10:15 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-22970)) + +> Jérémy MARQUER says: +> +> Hey. I cannot access to the new Preferences UI of CN1 with eclipse. My cn1 plugin version is “1.0.0.201608062027”. Thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Shai Almog** — August 10, 2016 at 5:37 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-22470)) + +> Shai Almog says: +> +> Hi, +> is this on a Mac or a PC? +> Are you using JDK 8 to run Eclipse (you need to set it up in eclipse.ini)? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Jérémy MARQUER** — August 10, 2016 at 7:09 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-22734)) + +> Jérémy MARQUER says: +> +> On a PC. Yes sure, I launch Eclipse with this flag +> “-vm +> C:/Program Files/Java/jre1.8.0_77/bin/javaw.exe” +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Shai Almog** — August 11, 2016 at 4:41 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-21456)) + +> Shai Almog says: +> +> Check that you have the GUIBuilder jar at c:myuserhomedir.codenameoneguibuilder_1.jar +> +> Assuming it’s there try running it from command line using java -jar c:myuserhomedir.codenameoneguibuilder_1.jar -settings path_to_project[codenameone_settings.proper…]() are there any errors printed to the console? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Jérémy MARQUER** — August 11, 2016 at 7:12 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-22557)) + +> Jérémy MARQUER says: +> +> As I expected, I obtain the old settings UI (not the latest I think) … +> (and no errors printed) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Shai Almog** — August 12, 2016 at 4:16 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-22903)) + +> Shai Almog says: +> +> That’s a problem. We’ll look into it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Jérémy MARQUER** — August 17, 2016 at 4:31 pm ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-22635)) + +> Jérémy MARQUER says: +> +> It’s ok, thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Julien Sosin** — December 5, 2017 at 3:24 pm ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-23705)) + +> Julien Sosin says: +> +> Hi ! +> +> How can I delete a lib ? I tried CodeScanner but it looks deprecated and I can’t build iOS app anymore :/ +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + + +### **Shai Almog** — December 6, 2017 at 9:11 am ([permalink](https://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html#comment-23713)) + +> Shai Almog says: +> +> Hi, +> there is currently no standard uninstaller but it shouldn’t be too hard. See the instructions I posted here: [https://stackoverflow.com/a…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomatically-install-update-distribute-cn1libs-extensions.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/automating-releases.md b/docs/website/content/blog/automating-releases.md new file mode 100644 index 0000000000..ee0198a8a7 --- /dev/null +++ b/docs/website/content/blog/automating-releases.md @@ -0,0 +1,122 @@ +--- +title: Automating Releases +slug: automating-releases +url: /blog/automating-releases/ +original_url: https://www.codenameone.com/blog/automating-releases.html +aliases: +- /blog/automating-releases.html +date: '2015-05-31' +author: Shai Almog +--- + +![Header Image](/blog/automating-releases/continuous-integration-1.png) + +Our website deployment has become even more complex thanks to the [demos section](/demos.html). +The crux of it is in updating the demos with every small update to the JavaScript build process which is why +we implemented a build option based on the work we did for our [CI (Jenkins) integration](/blog/continuous-integration.html). +This work essentially allows to build a Codename One app synchronously which is useful when you want +to do things such as continuous integration or release engineering. +Notice that the synchronous build feature is an enterprise only feature since its overuse can have a very heavy toll on our servers. + +Essentially we copied the existing build.xml to a separate file to prevent updates from overriding it. We then added +targets such as this for the kitchen sink: + + + + + + +This is effectively a copy and paste of the `build-for-javascript` target where we added the line +`automated="true"` to indicate that this build works in a singular process. +After the build completes we are left with a `result.zip` file in the `dist` folder. Which +we unzip to find all the files from the build server: + + + + + + + + + +While the sample above shows the JavaScript build target it can be applied to any of the Codename One build +targets and is remarkably useful for a release engineering process. When you need to release one version for all platforms +on a frequent basis even a minute automation like this makes a big difference. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Blessing Mahlalela** — February 9, 2017 at 4:35 pm ([permalink](https://www.codenameone.com/blog/automating-releases.html#comment-23223)) + +> Blessing Mahlalela says: +> +> Hi during development I noticed that if I try to send multiple builds ie Send Android, Send iOS.. on Netbeans etc. I would receive a compile error if I send them too quickly (simultaneously), I think CN1 deletes some files during the send build process. In any case the reason why I saying that is, I have Jenkins setup and would like to return a [result.zip]() containing multiple platform result files ie Android, iOS, Web, Desktop. How can I go about doing this on Jenkins build.xml? I am currently able to set ANT targets on Jenkins pre and post build. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomating-releases.html) + + +### **Shai Almog** — February 9, 2017 at 6:32 pm ([permalink](https://www.codenameone.com/blog/automating-releases.html#comment-21563)) + +> Shai Almog says: +> +> Yes, you can send concurrent builds but not at once. If you use automation to do this your user can’t send a build at that exact time. It’s just a limitation in the way the system was designed as the code that allocates a build needs to reserve a spot. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomating-releases.html) + + +### **Blessing Mahlalela** — February 9, 2017 at 6:43 pm ([permalink](https://www.codenameone.com/blog/automating-releases.html#comment-23319)) + +> Blessing Mahlalela says: +> +> Ok, I have now managed to call an ANT “build-for-javascript” target from the build xml. Thanks a lot for this, no more sitting and waiting for builds, secondly the automated test recorder will become a great resource to small dev organisations that just don’t have budget for dedicated test teams! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomating-releases.html) + + +### **Blessing Mahlalela** — February 9, 2017 at 6:46 pm ([permalink](https://www.codenameone.com/blog/automating-releases.html#comment-23071)) + +> Blessing Mahlalela says: +> +> One more question. How can I add multiple ANT arguments on Jenkins? I would like to automate the building of Android, iOS & web on every successful CI build. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomating-releases.html) + + +### **Blessing Mahlalela** — February 9, 2017 at 8:21 pm ([permalink](https://www.codenameone.com/blog/automating-releases.html#comment-23237)) + +> Blessing Mahlalela says: +> +> Managed to do multiple builds by adding additional ANT build steps. Had to configure signing certificates also. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomating-releases.html) + + +### **Shai Almog** — February 9, 2017 at 8:49 pm ([permalink](https://www.codenameone.com/blog/automating-releases.html#comment-23077)) + +> Shai Almog says: +> +> Yes we do them one by one since they are synchronous. I hope to write a more detailed blog on doing this in a future update just didn’t get around to doing it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautomating-releases.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/autorenewing-subscriptions-in-ios-and-android.md b/docs/website/content/blog/autorenewing-subscriptions-in-ios-and-android.md new file mode 100644 index 0000000000..328bba292a --- /dev/null +++ b/docs/website/content/blog/autorenewing-subscriptions-in-ios-and-android.md @@ -0,0 +1,829 @@ +--- +title: Auto-Renewing Subscriptions in iOS and Android +slug: autorenewing-subscriptions-in-ios-and-android +url: /blog/autorenewing-subscriptions-in-ios-and-android/ +original_url: https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html +aliases: +- /blog/autorenewing-subscriptions-in-ios-and-android.html +date: '2017-01-02' +author: Steve Hannah +--- + +![Header Image](/blog/autorenewing-subscriptions-in-ios-and-android/in-app-purchase.jpg) + +__ | This is the third post in a three-part series on In-App purchase. Please check out [Part I: Introduction to In-App Purchase](https://www.codenameone.com/blog/intro-to-in-app-purchase.html) and [Part 2: Implementing Non-Renewable Subscriptions](https://www.codenameone.com/blog/in-app-purchase-non-renewable-subscriptions.html). +---|--- + +Auto-renewable subscriptions provide, arguably, an easier path to recurring revenue than non-renewable subscriptions because all of the subscription stuff is handled by the app store. You defer almost entirely to the app store (iTunes for iOS, and Play for Android) for billing and management. + +If there is a down-side, it would be that you are also subject to the rules of each app store – and they take their cut of the revenue. On iOS, you keep 70% of the revenue for the first year of a subscription. This increases to 85% after the first year. Google also let’s you keep 70% of the revenue on subscriptions. I read a number of news articles from June 2016, stating that they [planned to increase this to 85%](http://www.androidauthority.com/devs-to-keep-85-percent-of-subscription-payments-697528/) to match Apple but I haven’t been able to find any corroborating information on the Play site itself, so at the time of writing, it appears that they are still on the 70/30 split model. + + 1. For more information about Apple’s auto-renewable subscription features and rules see [this document](https://developer.apple.com/app-store/subscriptions/). + + 2. For more information about subscriptions in Google play, see [this document](https://developer.android.com/google/play/billing/billing_subscriptions.html). + +## Auto-Renewable vs Non-Renewable. Best Choice? + +When deciding between auto-renewable and non-renewable subscriptions, as always, the answer will depend on your needs and preferences. Auto-renewables are nice because it takes the process completely out of your hands. You just get paid. On the other hand, there are valid reasons to want to use non-renewables. E.g. You can’t cancel an auto-renewable subscription for a user. They have to do that themselves. You may also want more control over the subscription and renewal process, in which case a non-renewable might make more sense. + +I recommend [this blog post](https://marco.org/2013/12/02/auto-renewable-subscriptions) for a well-informed, critical review of Apple’s auto-renew process. (TLDR> He says to **never** use auto-renewables). I don’t have as much experience with in-app purchase as that author, but from my experiments, the auto-renewable option seems like a perfectly good solution. + +## Learning By Example + +The remainder of this post describes the general workflow of subscription management on the server. It also demonstrates how use Apple’s and Google’s web services to validate receipts and stay informed of important events (such as when users cancel or renew their subscriptions). + +## Building the IAP Demo Project + +To aid in this process, I’ve created a fully-functional in-app purchase demo project that includes both a [client app](https://gist.github.com/shannah/b61b9b6b35ea0eac923a54163f5d4deb) and a [server app](https://github.com/shannah/cn1-iap-demo-server). + +### Setting up the Client Project + + 1. Create a new Codename One project in Netbeans, and choose the “Bare-bones Hello World Template”. You should make your package name something unique so that you are able to create real corresponding apps in both Google Play and iTunes connect. + + 2. Once the project is created, copy [this source file](https://gist.github.com/shannah/b61b9b6b35ea0eac923a54163f5d4deb) contents into your main class file. Then change the package name, and class name in the file to match your project settings. E.g. change `package ca.weblite.iapdemo;` to `package ;` and `class IAPDemo implements PurchaseCallback` to `class YourClassName implements PurchaseCallback`. + + 3. Add the [Generic Web Service Client](https://github.com/shannah/cn1-generic-webservice-client) library to your project by going to “Codename Settings” > “Extensions”, finding that library, and click “Download”. Then “Refresh CN1 libs” as it suggests. + + 4. Change the `localHost` property to point to your local machine’s network address. Using “http://localhost” is not going to cut it here because when the app is running on a phone, it needs to be able to connect to your web server over the network. This address will be your local network address (e.g. 192.168.0.9, or something like that). + + private static final String localHost = "http://10.0.1.32"; + + 5. Add the `ios.plistInject` build hint to your project with the value “NSAppTransportSecurity NSAllowsArbitraryLoads ”. This is so that we can use http urls in iOS. Since we don’t intend to full publish this app, we can cut corners like this. If you were creating a real app, you would use proper secure URLs. + +__ | In the client project, you’ll notice some places where we use `Purchase.purchase(sku)` for purchasing a product, and other places where we use `Purchase.subscribe(sku)`. The correct method will depend on how you have set up the product in the Google Play store. If the product is set up as a subscription, you **must** use `subscribe()`. Otherwise, you should use `purchase()`. +---|--- + +### Setting up the Server Project + +Download the CN1-IAP-Server demo project from Github, and run its “install-deps” ANT task in order to download and install its dependencies to your local Maven repo. + +__ | For the following commands to work, make sure you have “ant”, “mvn”, and “git” in your environment PATH. +---|--- + + + $ git clone https://github.com/shannah/cn1-iap-demo-server + $ cd cn1-iap-demo-server + $ ant install-deps + +Open the project in Netbeans + +### Setting up the Database + + 1. Create a new database in your preferred DBMS. Call it anything you like. + + 2. Create a new table named “RECEIPTS” in this database with the following structure: + + create TABLE RECEIPTS + ( + TRANSACTION_ID VARCHAR(128) not null, + USERNAME VARCHAR(64) not null, + SKU VARCHAR(128) not null, + ORDER_DATA VARCHAR(32000), + PURCHASE_DATE BIGINT, + EXPIRY_DATE BIGINT, + CANCELLATION_DATE BIGINT, + LAST_VALIDATED BIGINT, + STORE_CODE VARCHAR(20) default '' not null, + primary key (TRANSACTION_ID, STORE_CODE) + ) + + 3. Open the “persistence.xml” file in the server netbeans project. + +![Persistence File](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-persistence-file.png) + + 4. Change the data source to the database you just created. + +![Edit persistence.xml file data source](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-persistence-file.png) + +If you’re not sure how to create a data source, see my [previous tutorial on connecting to a MySQL database](https://www.codenameone.com/blog/connecting-to-a-mysql-database-part-2.html). + +### Testing the Project + +At this point we should be able to test out the project in the Codename One simulator to make sure it is working. + + 1. Build and Run the server project in Netbeans. You may need to tell it which application server you wish to run it on. I am running it on the Glassfish 4.1 that comes bundled with Netbeans. + + 2. Build and run the client project in Netbeans. This should open the Codename One simulator. + +When the app first opens you’ll see a screen as follows: + +![First screen of app](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-first-screen.png) + +This screen is for testing consumable products, so we won’t be making use of this right now. + +Open the hamburger menu and select “Subscriptions”. You should see something like this: + +![Subscriptions form](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-subscriptions-form.png) + +Click on the “Subscribe 1 Month No Ads” button. You will be prompted to accept the purchase: + +![Approve purchase dialog](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-approve-purchase.png) + +Upon completion, the app will submit the purchase to your server, and if all went well, it will retrieve the updated list of receipts from your server also, and update the label on this form to say “No Ads. Expires ”: + +![After successful purchase](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-successful-purchase.png) + +__ | This project is set up to use an expedited expiry date schedule for purchases from the simulator. 1 month = 5 minutes. 3 months = 15 minutes. This helps for testing. That is why your expiry date may be different than expected. +---|--- + +Just to verify that the receipt was inserted correctly, you should check the contents of your “RECEIPTS” table in your database. In Netbeans, I can do this easily from the “Services” pane. Expand the database connection down to the RECEIPTS table, right click “RECEIPTS” and select “View Data”. This will open a data table similar the the following: + +![Receipts table after insertion](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-view-table-data.png) + +![Table view](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-table-view.png) + +A few things to mention here: + + 1. The “username” was provided by the client. It is hard-coded to “admin”, but the idea is that you would have the user log in and you would have access to their real username. + + 2. All dates are stored as unix timestamps in milliseconds. + +If you delete the receipt from your database, then press the “Synchronize Receipts” button in your app, the app will again say “No subscriptions.” Similarly if you wait 5 minutes and hit “Synchronize receipts” the app will say no subscriptions found, and the “ads” will be back. + +#### Troubleshooting + +Let’s not pretend that everything worked for you on the first try. There’s a lot that could go wrong here. If you make a purchase and nothing appears to happen, the first thing you should do is check the Network Monitor in the simulator (“Simulate” > “Network” > “Network Monitor”). You should see a list of network requests. Some will be GET requests and there will be at least one POST request. Check the response of these requests to see if they succeeded. + +Also check the Glassfish server log to see if there is an exception. + +Common problems would be that the URL you have set in the client app for `endpointURL` is incorrect, or that there is a database connection problem. + +## Looking at the Source of the App + +Now that we’ve set up and built the app, let’s take a look at the source code so you can see how it all works. + +### Client Side + +I use the [Generic Webservice Client Library](https://github.com/shannah/cn1-generic-webservice-client) from inside my `ReceiptStore` implementation to load receipts from the web service, and insert new receipts to the database. + +The source for my ReceiptStore is as follows: + + + private ReceiptStore createReceiptStore() { + return new ReceiptStore() { + + RESTfulWebServiceClient client = createRESTClient(receiptsEndpoint); + + @Override + public void fetchReceipts(SuccessCallback callback) { + RESTfulWebServiceClient.Query query = new RESTfulWebServiceClient.Query() { + + @Override + protected void setupConnectionRequest(RESTfulWebServiceClient client, ConnectionRequest req) { + super.setupConnectionRequest(client, req); + req.setUrl(receiptsEndpoint); + } + + }; + client.find(query, rowset->{ + List out = new ArrayList(); + for (Map m : rowset) { + Result res = Result.fromContent(m); + Receipt r = new Receipt(); + r.setTransactionId(res.getAsString("transactionId")); + r.setPurchaseDate(new Date(res.getAsLong("purchaseDate"))); + r.setQuantity(1); + r.setStoreCode(m.getAsString("storeCode")); + r.setSku(res.getAsString("sku")); + + if (m.containsKey("cancellationDate") && m.get("cancellationDate") != null) { + r.setCancellationDate(new Date(res.getAsLong("cancellationDate"))); + } + if (m.containsKey("expiryDate") && m.get("expiryDate") != null) { + r.setExpiryDate(new Date(res.getAsLong("expiryDate"))); + } + out.add(r); + + } + callback.onSucess(out.toArray(new Receipt[out.size()])); + }); + } + + @Override + public void submitReceipt(Receipt r, SuccessCallback callback) { + Map m = new HashMap(); + m.put("transactionId", r.getTransactionId()); + m.put("sku", r.getSku()); + m.put("purchaseDate", r.getPurchaseDate().getTime()); + m.put("orderData", r.getOrderData()); + m.put("storeCode", r.getStoreCode()); + client.create(m, callback); + } + + }; + } + +Notice that we are not doing any calculation of expiry dates in our client app, as we did in the previous post (on non-renewable receipts). Since we are using a server now, it makes sense to move all of that logic over to the server. + +The `createRESTClient()` method shown there simply creates a `RESTfulWebServiceClient` and configuring it to use basic authentication with a username and password. The idea is that your user would have logged into your app at some point, and you would have a username and password on hand to pass back to the web service with the receipt data so that you can connect the subscription to a user account. The source of that method is listed here: + + + /** + * Creates a REST client to connect to a particular endpoint. The REST client + * generated here will automatically add the Authorization header + * which tells the service what platform we are on. + * @param url The url of the endpoint. + * @return + */ + private RESTfulWebServiceClient createRESTClient(String url) { + return new RESTfulWebServiceClient(url) { + + @Override + protected void setupConnectionRequest(ConnectionRequest req) { + try { + req.addRequestHeader("Authorization", "Basic " + Base64.encode((getUsername()+":"+getPassword()).getBytes("UTF-8"))); + } catch (Exception ex) {} + } + + }; + } + +### Server-Side + +On the server-side, our REST controller is a standard JAX-RS REST interface. I used Netbeans web service wizard to generate it and then modified it to suit my purposes. The methods of the `ReceiptsFacadeREST` class pertaining to the REST API are shown here: + + + @Stateless + @Path("com.codename1.demos.iapserver.receipts") + public class ReceiptsFacadeREST extends AbstractFacade { + + // ... + + @POST + @Consumes({"application/xml", "application/json"}) + public void create(Receipts entity) { + + String username = credentialsWithBasicAuthentication(request).getName(); + entity.setUsername(username); + + // Save the receipt first in case something goes wrong in the validation stage + super.create(entity); + + // Let's validate the receipt + validateAndSaveReceipt(entity); + // validates the receipt against appropriate web service + // and updates database if expiry date has changed. + } + + // ... + @GET + @Override + @Produces({"application/xml", "application/json"}) + public List findAll() { + String username = credentialsWithBasicAuthentication(request).getName(); + return getEntityManager() + .createNamedQuery("Receipts.findByUsername") + .setParameter("username", username) + .getResultList(); + } + +The magic happens inside that `validateAndSaveReceipt()` method, which I’ll cover in detail later on in this post. + +#### Notifications + +It is important to note that you will not be notified by apple or google when changes are made to subscriptions. It is up to you to periodically “poll” their web service to find if any changes have been made. Changes we would be interested in are primarily renewals and cancellations. In order to deal with this, set up a method to run periodically (once-per day might be enough). For testing, I actually set it up to run once per minute as shown below: + + + private static final long ONE_DAY = 24 * 60 * 60 * 1000; + private static final long ONE_DAY_SANDBOX = 10 * 1000; + @Schedule(hour="*", minute="*") + public void validateSubscriptionsCron() { + System.out.println("----------- DOING TIMED TASK ---------"); + List res = null; + final Set completedTransactionIds = new HashSet(); + for (String storeCode : new String[]{Receipt.STORE_CODE_ITUNES, Receipt.STORE_CODE_PLAY}) { + while (!(res = getEntityManager().createNamedQuery("Receipts.findNextToValidate") + .setParameter("threshold", System.currentTimeMillis() - ONE_DAY_SANDBOX) + .setParameter("storeCode", storeCode) + .setMaxResults(1) + .getResultList()).isEmpty() && + !completedTransactionIds.contains(res.get(0).getTransactionId())) { + + final Receipts curr = res.get(0); + completedTransactionIds.add(curr.getTransactionId()); + Receipts[] validatedReceipts = validateAndSaveReceipt(curr); + em.flush(); + for (Receipts r : validatedReceipts) { + completedTransactionIds.add(r.getTransactionId()); + } + + } + } + } + +That method simply finds all of the receipts in the database that haven’t been validated in some period of time, and validates it. Again, the magic happens inside the `validateAndSaveReceipt()` method which we cover later. + +__ | In this example we only validate receipts from the iTunes and Play stores because those are the only ones that we currently support auto-renewing subscriptions on. +---|--- + +## The CN1-IAP-Validator Library + +For the purpose of this tutorial, I created a library to handle receipt validation in a way that hides as much of the complexity as possible. It supports both Google Play receipts and iTunes receipts. + +The general usage is as follows: + + + IAPValidator validator = IAPValidator.getValidatorForPlatform(receipt.getStoreCode()); + if (validator == null) { + // no validators were found for this store + // Do custom validation + } else { + validator.setAppleSecret(APPLE_SECRET); + validator.setGoogleClientId(GOOGLE_DEVELOPER_API_CLIENT_ID); + validator.setGooglePrivateKey(GOOGLE_DEVELOPER_PRIVATE_KEY); + Receipt[] result = validator.validate(receipt); + ... + } + +As you can see from this snippet, the complexity of receipt validation has been reduced to entering three configuration strings: + + 1. `APPLE_SECRET` – This is a “secret” string that you will get from iTunes connect when you set up your in-app products. + + 2. `GOOGLE_DEVELOPER_API_CLIENT_ID` – A client ID that you’ll get from the google developer API console when you set up your API service credentials. + + 3. `GOOGLE_DEVELOPER_PRIVATE_KEY` – A PKCS8 encoded string with an RSA private key that you’ll receive at the same time as the `GOOGLE_DEVELOPER_API_CLIENT_ID`. + +I will go through the steps to obtain these values later on in this post. + +## The `validateAndSaveReceipt()` Method + +You are now ready to see the full magic of the `validateAndSaveReceipt()` method in all its glory: + + + /** + * Validates a given receipt, updating the expiry date, + * @param receipt The receipt to be validated + * @param forInsert If true, then an expiry date will be calculated even if there is no validator. + */ + private Receipts[] validateAndSaveReceipt(Receipts receipt) { + EntityManager em = getEntityManager(); + Receipts managedReceipt = getManagedReceipt(receipt); + // managedReceipt == receipt if receipt is in database or null otherwise + + if (Receipt.STORE_CODE_SIMULATOR.equals(receipt.getStoreCode())) { __**(1)** + if (receipt.getExpiryDate() == null && managedReceipt == null) { + //Not inserted yet and no expiry date set yet + Date dt = calculateExpiryDate(receipt.getSku(), true); + if (dt != null) { + receipt.setExpiryDate(dt.getTime()); + } + } + if (managedReceipt == null) { + // Receipt is not in the database yet. Add it + em.persist(receipt); + return new Receipts[]{receipt}; + } else { + // The receipt is already in the database. Update it. + em.merge(managedReceipt); + return new Receipts[]{managedReceipt}; + } + } else { + // It is not a simulator receipt + IAPValidator validator = IAPValidator.getValidatorForPlatform(receipt.getStoreCode()); + if (validator == null) { + // Receipt must have come from a platform other than iTunes or Play + // Because there is no validator + + if (receipt.getExpiryDate() == null && managedReceipt == null) { + // No expiry date. + // Generate one. + Date dt = calculateExpiryDate(receipt.getSku(), false); + if (dt != null) { + receipt.setExpiryDate(dt.getTime()); + } + + } + if (managedReceipt == null) { + em.persist(receipt); + return new Receipts[]{receipt}; + } else { + em.merge(managedReceipt); + return new Receipts[]{managedReceipt}; + } + + } + + // Set credentials for the validator + validator.setAppleSecret(APPLE_SECRET); + validator.setGoogleClientId(GOOGLE_DEVELOPER_API_CLIENT_ID); + validator.setGooglePrivateKey(GOOGLE_DEVELOPER_PRIVATE_KEY); + + // Create a dummy receipt with only transaction ID and order data to pass + // to the validator. Really all it needs is order data to be able to validate + Receipt r2 = Receipt(); + r2.setTransactionId(receipt.getTransactionId()); + r2.setOrderData(receipt.getOrderData()); + try { + Receipt[] result = validator.validate(r2); + // Depending on the platform, result may contain many receipts or a single receipt + // matching our receipt. In the case of iTunes, none of the receipt transaction IDs + // might match the original receipt's transactionId because the validator + // will set the transaction ID to the *original* receipt's transaction ID. + // If none match, then we should remove our receipt, and update each of the returned + // receipts in the database. + Receipt matchingValidatedReceipt = null; + for (Receipt r3 : result) { + if (r3.getTransactionId().equals(receipt.getTransactionId())) { + matchingValidatedReceipt = r3; + break; + } + } + + if (matchingValidatedReceipt == null) { + // Since the validator didn't find our receipt, + // we should remove the receipt. The equivalent + // is stored under the original receipt's transaction ID + if (managedReceipt != null) { + em.remove(managedReceipt); + managedReceipt = null; + } + } + List out = new ArrayList(); + // Now go through and + for (Receipt r3 : result) { + if (r3.getOrderData() == null) { + // No order data found in receipt. Setting it to the original order data + r3.setOrderData(receipt.getOrderData()); + } + Receipts eReceipt = new Receipts(); + eReceipt.setTransactionId(r3.getTransactionId()); + eReceipt.setStoreCode(receipt.getStoreCode()); + Receipts eManagedReceipt = getManagedReceipt(eReceipt); + if (eManagedReceipt == null) { + copy(eReceipt, r3); + eReceipt.setUsername(receipt.getUsername()); + eReceipt.setLastValidated(System.currentTimeMillis()); + em.persist(eReceipt); + out.add(eReceipt); + } else { + + copy(eManagedReceipt, r3); + eManagedReceipt.setUsername(receipt.getUsername()); + eManagedReceipt.setLastValidated(System.currentTimeMillis()); + em.merge(eManagedReceipt); + out.add(eManagedReceipt); + } + } + + return out.toArray(new Receipts[out.size()]); + + } catch (Exception ex) { + // We should probably store some info about the failure in the + // database to make it easier to find receipts that aren't validating, + // but for now we'll just log it. + Log.p("Failed to validate receipt "+r2); + Log.p("Reason: "+ex.getMessage()); + Log.e(ex); + return new Receipts[]{receipt}; + + } + } + } + +__**1** | We need to handle the case where the app is being used in the CN1 simulator. We’ll treat this +as a non-renewable receipt, and we’ll calculate the expiry date using an “accelerated” clock to assist in testing. +---|--- + +__ | In many of the code snippets for the Server-side code, you’ll see references to both a `Receipts` class and a `Receipt` class. I know this is slightly confusing. The `Receipts` class is a JPA entity the encapsulates a row from the “receipts” table of our SQL database. The `Receipt` class is `com.codename1.payment.Receipt`. It is used to interface with the IAP validation library. +---|--- + +## Google Play Setup + +### Creating the App in Google Play + +In order to test out in-app purchase on an Android device, you’ll need to create an app the [Google Play Developer Console](https://play.google.com/apps/publish/). I won’t describe the process in this post, but there is plenty of information around the internet on how to do this. Some useful references for this include: + + 1. [Getting Started With Publishing](https://developer.android.com/distribute/googleplay/start.html) – If you don’t already have an account with Google to publish your apps. + + 2. [Launch Checklist](https://developer.android.com/distribute/tools/launch-checklist.html) + +#### Graphics, Icons, etc.. + +You are required to upload some screenshots and feature graphics. Don’t waste time making these perfect. For the screenshots, you can just use the “Screenshot” option in the simulator. (Use the Nexus 5 skin). For the feature graphics, I used [this site](https://www.norio.be/android-feature-graphic-generator/) that will generate the graphics in the correct dimensions for Google Play. You can also just leave the icon as the default Codename One icon. + +#### Creating Test Accounts + +__ | You cannot purchase in-app products from your app using your publisher account. You need to set up at least one test account for the purpose of testing the app. +---|--- + +In order to test your app, you need to set up a test account. A test account must be associated with a real gmail email address. If you have a domain that is managed by Google apps, then you can also use an address from that domain. + +The full process for testing in-app billing can be found in [this google document](https://developer.android.com/google/play/billing/billing_testing.html). However, I personally found this documentation difficult to follow. + +For your purposes, you’ll need to set up a tester list in Google Play. Choose “Settings” > “Tester Lists”. Then create a list with all of the email address that you want to have treated as test accounts. Any purchases made by these email addresses will be treated as “Sandbox” purchases, and won’t require real money to change hands. + +#### Alpha Channel Distribution + +In order to test in-app purchase on Android, you **must** first publish your app. You can’t just build and install your app manually. The app needs to be published on the Play store, and it must be installed **through** the play store for in-app purchase to work. Luckily you can publish to an Alpha channel so that your app won’t be publicly available. + +For more information about setting up alpha testing on Google play see [this Google support document on the subject](https://support.google.com/googleplay/android-developer/answer/3131213?hl=en). + +Once you have set your app up for alpha testing, you can send an invite link to your test accounts. You can find the link in the Google Play console under the APK section, under the “Alpha” tab (and assuming you’ve enabled alpha testing. + +![Alpha testing tab in google play](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-alpha-testing-tab.png) + +The format of the link is `[https://play.google.com/apps/testing/](https://play.google.com/apps/testing/ “Owner” for now just so we don’t run into permissions issues. You’ll probably want to investigate further to fine a more limited role that only allows receipt verification, but for now, I don’t want any unnecessary road blocks for getting this to work. We’re probably going to run into “permission denied” errors at first anyways, so the fewer reasons for this, the better. + + 8. It will auto-generate an account ID for you. + + 9. Finally, for the “Key type”, select “JSON”. Then click the “Create” button. + +This should prompt the download of a JSON file that will have contents similar to the following: + + + { + "type": "service_account", + "project_id": "iapdemo-152500", + "private_key_id": "1b1d39f2bc083026b164b10a444ff7d839826b8a", + "private_key": "-----BEGIN PRIVATE KEY----- ... some private key string -----END PRIVATE KEY-----n", + "client_email": "[[email protected]](/cdn-cgi/l/email-protection)", + "client_id": "117601572633333082772", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://accounts.google.com/o/oauth2/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/iapdemo%40iapdemo-152500.iam.gserviceaccount.com" + } + +This is where we get the information we’re looking for. The “client_email” is what we’ll use for your `googleClientId`, and the “private_key” is what we’ll use for the `googlePrivateKey`. + +__ | Use the “client_email” value as our client ID, not the “client_id” value as you might be tempted to do. +---|--- + +We’ll set these in our constants: + + + public static final String GOOGLE_DEVELOPER_API_CLIENT_ID="[[email protected]](/cdn-cgi/l/email-protection)"; + public static final String GOOGLE_DEVELOPER_PRIVATE_KEY="-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----n"; + + ... + + validator.setGoogleClientId(GOOGLE_DEVELOPER_API_CLIENT_ID); + validator.setGooglePrivateKey(GOOGLE_DEVELOPER_PRIVATE_KEY); + +**NOT DONE YET** + +Before we can use these credentials to verify receipts for our app, we need to link our app to this new service account from within Google Play. + +Steps: + + 1. Open the [Google Play Developer Console](https://play.google.com/apps/publish/), then click on “Settings” > “API Access”. + + 2. You should see your app listed on this page. Click the “Link” button next to your app. + +![Link to API](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-link-to-api.png) + + 3. This should reveal some more options on the page. You should see a “Service Accounts” section with a list of all of the service accounts that you have created. Find the one we just created, and click the “Grant Access” button in its row. + +![Grant access](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-grant-access.png) + + 4. This will open a dialog titled “Add New User”. Leave everything default, except change the “Role” to “Administrator”. This provides “ALL” permissions to this account, which probably isn’t a good idea for production. Later on, after everything is working, you can circle back and try to refine permissions. For the purpose of this tutorial, I just want to pull out all of the potential road blocks. + +![New User](/blog/autorenewing-subscriptions-in-ios-and-android/iap3-new-user.png) + + 5. Press the “Add User” button. + +At this point, the service account **should** be active so we can try to validate receipts. + +#### Testing Receipt Validation + +The `ReceiptsFacadeREST` class includes a flag to enable/disable play store validation. By default it is disabled. Let’s enable it: + + + public static final boolean DISABLE_PLAY_STORE_VALIDATION=true; + +Change this to `false`. + +Then build and run the server app. The `validateSubscriptionsCron()` method is set to run once per minute, so we just need to wait for the timer to come up and it should try to validate all of the play store receipts. + +__ | I’m assuming you’ve already added a receipt in the previous test that we did. If necessary, you should purchase the subscription again in your app. +---|--- + +After a minute or so, you should see “———– VALIDATING RECEIPTS ———” written in the Glassfish log, and it will validate your receipts. If it works, your receipt’s expiry date will get populated in the database, and you can press “Synchronize Receipts” in your app to see this reflected. If it fails, there will like be a big ugly stack trace and exception readout with some clues about what went wrong. + +Realistically, your first attempt will fail for some reason. Use the error codes and stack traces to help lead you to the problem. And feel free to post questions here. + +## iTunes Connect Setup + +The process for setting up and testing your app on iOS is much simpler than on Android (IMHO). It took me a couple hours to get the iTunes version working, vs a couple days on the Google Play side of things. One notable difference that makes things simpler is that you don’t need to actually upload your app to the store to test in-app purchase. You can just use your debug build on your device. It is also **much** easier to roll a bunch of test accounts than on Google Play. You don’t need to set up an alpha program, you just create a few “test accounts” (and this is easy to do) in your iTunes connect account, and then make sure to use one of these accounts when making a purchase. You can easily switch accounts on your device from the “Settings” app, where you can just log out of the iTunes store – which will cause you to be prompted in your app the next time you make a purchase. + +### Setting up In-App Products + +The process to add products in iTunes connect is outlined [in this apple developer document](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/iTunesConnectInAppPurchase_Guide/Chapters/CreatingInAppPurchaseProducts.html#//apple_ref/doc/uid/TP40013727-CH3-SW1). We’ll add our two SKUs: + + 1. **iapdemo.noads.month.auto** – The 1 month subscription. + + 2. **iapdemo.noads.3month.auto** – The 3 month subscription. + +Just make sure you add them as auto-renewable subscriptions, and that you specify the appropriate renewal periods. Use the SKU as the product ID. Both of these products will be added to the same subscription group. Call the group whatever you like. + +### Creating Test Accounts + +In order to test purchases, you need to create some test accounts. See [this apple document](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SettingUpUserAccounts.html#//apple_ref/doc/uid/TP40011225-CH25-SW10) for details on how to create these test accounts. Don’t worry, the process is much simpler than for Android. It should take you under 5 minutes. + +Once you have the test accounts created, you should be set to test the app. + + 1. Make sure your server is running. + + 2. Log out from the app store. The process is described [here](https://support.apple.com/en-ca/HT203983). + + 3. Open your app. + + 4. Try to purchase a 1-month subscription + +If all went well, you should see the receipt listed in the RECEIPTS table of your database. But the expiry date will be null. We need to set up receipt verification in order for this to work. + +### Setting up Receipt Verification + +In order for receipt verification to work we simply need to generate a shared secret in iTunes connect. The process is described [here](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/iTunesConnectInAppPurchase_Guide/Chapters/CreatingInAppPurchaseProducts.html). + +Once you have a shared secret, update the ReceiptsFacadeREST class with the value: + + + public static final String APPLE_SECRET = "your-shared-secret-here"; + +And enable iTunes store validation: + + + public static final boolean DISABLE_ITUNES_STORE_VALIDATION=true; + +Change this to `false`. + +If you rebuild and run the server project, and wait for the `validateSubscriptionsCron()` method to run, it should validate the receipt. After about a minute (or less), you’ll see the text “———– VALIDATING RECEIPTS ———” written to the Glassfish log file, followed by some output from connecting to the iTunes validation service. If all went well, you should see your receipt expiration date updated in the database. If not, you’ll likely see some exception stack traces in the Glassfish log. + +__ | Sandbox receipts in the iTunes store are set to run on an accelerated schedule. A 1 month subscription is actually 5 minutes, 3 months is 15 minutes etc…​ Also sandbox subscriptions don’t seem to persist in perpetuity until the user has cancelled it. I have found that they usually renew only 4 or 5 times before they are allowed to lapse by Apple. +---|--- + +## Summary + +Setting up in-app purchase is not for the faint of heart. Having to jump through a battery of hoops on Android is poison for the soul. On the other hand, it may all just be worth it. Once you have a working system up and running, it can **mostly** continue to run on its own. Despite the length of this post, I’m really only just scratching the surface on this topic. There are many other aspects that I simply ignored due to time constraints. I encourage you to take the code in this post and try to make it work for yourself. You’re in for some pain, but I guarantee that the reward at the end of it all is worth it. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — January 3, 2017 at 9:19 pm ([permalink](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html#comment-23265)) + +> Thanks Steve – great tutorial. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautorenewing-subscriptions-in-ios-and-android.html) + + +### **salah Alhaddabi** — August 13, 2017 at 9:46 pm ([permalink](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html#comment-23501)) + +> Dear Steve, +> when I try to run the demo client, I get the following erros: (I have changed the package name to be com.salah.trails.iapdemo.IAPDemo) +> +> java.lang.ClassNotFoundException: com.salah.trails.iapdemo.IAPDemo +> at java.net.URLClassLoader.findClass([URLClassLoader.java]():381) +> at java.lang.ClassLoader.loadClass([ClassLoader.java]():424) +> at sun.misc.Launcher$AppClassLoader.loadClass([Launcher.java]():331) +> at java.lang.ClassLoader.loadClass([ClassLoader.java]():357) +> at java.lang.ClassLoader.findSystemClass([ClassLoader.java]():1001) +> at com.codename1.impl.javase.ClassPathLoader.findClass([ClassPathLoader.java]():100) +> at com.codename1.impl.javase.ClassPathLoader.loadClass([ClassPathLoader.java]():50) +> at java.lang.Class.forName0(Native Method) +> at java.lang.Class.forName([Class.java]():264) +> at com.codename1.impl.javase.Executor$[1.run](:86) +> at java.awt.event.InvocationEvent.dispatch([InvocationEvent.java]():311) +> at java.awt.EventQueue.dispatchEventImpl([EventQueue.java]():756) +> at java.awt.EventQueue.access$500([EventQueue.java]():97) +> at java.awt.EventQueue$[3.run](:709) +> at java.awt.EventQueue$[3.run](:703) +> at java.security.AccessController.doPrivileged(Native Method) +> at java.security.ProtectionDomain$1.doIntersectionPrivilege([ProtectionDomain.java]():75) +> at java.awt.EventQueue.dispatchEvent([EventQueue.java]():726) +> at java.awt.EventDispatchThread.pumpOneEventForFilters([EventDispatchThread.java]():201) +> at java.awt.EventDispatchThread.pumpEventsForFilter([EventDispatchThread.java]():116) +> at java.awt.EventDispatchThread.pumpEventsForHierarchy([EventDispatchThread.java]():105) +> at java.awt.EventDispatchThread.pumpEvents([EventDispatchThread.java]():101) +> at java.awt.EventDispatchThread.pumpEvents([EventDispatchThread.java]():93) +> at [java.awt.EventDispatchThrea…](:82) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautorenewing-subscriptions-in-ios-and-android.html) + + +### **Shai Almog** — August 14, 2017 at 7:04 am ([permalink](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html#comment-23511)) + +> You refactored the package name without updating it in the [codenameone_settings.proper…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautorenewing-subscriptions-in-ios-and-android.html) + + +### **Brenden** — June 11, 2019 at 9:15 am ([permalink](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html#comment-24009)) + +> Dear Steve +> +> Above it says that there is no need to upload your app to the apple store to test the app , is this still valid now in 2019 ? or has this changed ? +> +> Regards Brenden +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautorenewing-subscriptions-in-ios-and-android.html) + + +### **Shai Almog** — June 12, 2019 at 4:11 am ([permalink](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html#comment-24099)) + +> Hi, +> it should work fine locally but you need to still configure everything in itunes connect otherwise it won’t work. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautorenewing-subscriptions-in-ios-and-android.html) + + +### **Rochana Sawatzky** — November 27, 2019 at 1:36 am ([permalink](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html#comment-24269)) + +> Hey Steve – no matter what I seem to do, when trying to ant-install deps I get the error: +> +> Cannot run program “mvn” (in directory …”): CreateProcess error=2, The system cannot find the file specified +> +> I have installed maven, and added it to my path, as well as adding maven_home, m2_home, java_home environment variables. I can run mvn -version fine, so I’m at a loss for why I’m getting the error. Any ideas? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautorenewing-subscriptions-in-ios-and-android.html) + + +### **Shai Almog** — November 27, 2019 at 2:59 am ([permalink](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html#comment-24267)) + +> If you added it to the path in Windows GUI it might not impact the currently open shell. If you’re using windows shell this might conflict with spaces you have in the path so make sure you use quotes e.g. `set PATH=”PATH TO MAVEN”;%PATH%` +> +> If this doesn’t help try to provide more details about your environment so we can help. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautorenewing-subscriptions-in-ios-and-android.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/autosizing-add-all-ios-redirects.md b/docs/website/content/blog/autosizing-add-all-ios-redirects.md new file mode 100644 index 0000000000..47757d71e0 --- /dev/null +++ b/docs/website/content/blog/autosizing-add-all-ios-redirects.md @@ -0,0 +1,329 @@ +--- +title: Autosizing, Add All & iOS Redirects +slug: autosizing-add-all-ios-redirects +url: /blog/autosizing-add-all-ios-redirects/ +original_url: https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html +aliases: +- /blog/autosizing-add-all-ios-redirects.html +date: '2017-02-07' +author: Shai Almog +--- + +![Header Image](/blog/autosizing-add-all-ios-redirects/new-features-5.jpg) + +One of the common requests we received over the years is a way to let text “fit” into the allocated space so the font will match almost exactly the width available. In some designs this is very important but it’s also very tricky. Measuring the width of a String is a surprisingly expensive operation on some OS’s. Unfortunately, there is no other way other than trial & error to find the “best size”. + +Still despite the fact that something is “slow” we might still want to use it for some cases, this isn’t something you should use in a renderer, infinite scroll etc. and we recommend minimizing the usage of this feature as much as possible. + +This feature is only applicable to `Label` and its subclasses (e.g. `Button`), with components such as `TextArea` (e.g. `SpanButton`) the choice between shrinking and line break would require some complex logic. + +To activate this feature just use `setAutoSizeMode(true)` e.g.: + + + Form hi = new Form("AutoSize", BoxLayout.y()); + + Label a = new Label("Short Text"); + a.setAutoSizeMode(true); + Label b = new Label("Much Longer Text than the previous line..."); + b.setAutoSizeMode(true); + Label c = new Label("MUCH MUCH MUCH Much Longer Text than the previous line by a pretty big margin..."); + c.setAutoSizeMode(true); + + Label a1 = new Button("Short Text"); + a1.setAutoSizeMode(true); + Label b1 = new Button("Much Longer Text than the previous line..."); + b1.setAutoSizeMode(true); + Label c1 = new Button("MUCH MUCH MUCH Much Longer Text than the previous line by a pretty big margin..."); + c1.setAutoSizeMode(true); + hi.addAll(a, b, c, a1, b1, c1); + + hi.show(); + +![Automatically sizes the fonts of the buttons/labels based on text and available space](/blog/autosizing-add-all-ios-redirects/autosize.png) + +Figure 1. Automatically sizes the fonts of the buttons/labels based on text and available space + +### Add All + +You will notice in the code above we added a new method: `addAll`. + +`addAll` is a shortcut that allows the code above to be written as: + + + hi.addAll(a, b, c, a1, b1, c1); + +Instead of the more verbose syntax: + + + hi.add(a). + add(b). + add(c). + add(a1). + add(b1). + add(c1); + +It’s not a huge difference but at least when building demos/test cases it’s nice. + +### Redirects on iOS + +One of the big decisions we made in Codename One was to not copy `java.io` wholesale. This has been a double edged sword…​ + +It has made us far more portable and also provided reliability that no other competing service can match in terms of networking. However, the differences within the network stack between OS’s are second only to the GUI differences. One such painful difference is the fact that iOS requires HTTPS now. + +Another such painful difference is redirect behavior. Codename One handles redirect by returning the 30x HTTP response and redirecting seamlessly. However, you can override that behavior and grab the 30x redirect. This also means the behavior of redirect (which is one of those gray areas in HTTP implementations) is consistent. + +But this isn’t the case on iOS where it handles redirect internally and we are faced with this after the fact. + +In the past we evaluated this and determined that this wouldn’t be an easy fix, I’m not sure if this is something we missed or something that changed in recent iOS versions but it looks like the fix isn’t as hard as we feared as we got this [pull request](https://github.com/codenameone/CodenameOne/pull/2030) & merged it. + +We might still revert this fix if we run into too many problems so with this Friday update check out your networking code and make sure everything is in order, if not we might need to provide a build hint to toggle this. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **João Bastos** — February 13, 2017 at 12:32 pm ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-23210)) + +> Is the addAll shortcut already available? Cant see it in netbeans… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Shai Almog** — February 14, 2017 at 8:05 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-23119)) + +> Shai Almog says: +> +> It should be. Use the Update Client Libs button in Codename One Settings. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **João Bastos** — February 14, 2017 at 5:23 pm ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24230)) + +> João Bastos says: +> +> Solved! Thanks Shai! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Denis** — September 20, 2018 at 8:06 pm ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24001)) + +> Denis says: +> +> Hi Shai, +> +> setAutoSizeMode(true) doesn’t work for my app, more over it makes text to disappear +> please take at screenshots, this is before AutoSize set to true, text is very tiny in tablets +> [https://uploads.disquscdn.c…]() +> and this is after AutoSize set to true for first (top) label +> [https://uploads.disquscdn.c…]() +> +> what can a reason for that ? +> +> Thanks, +> Denis +> +> p.s. CodenameOne version 5.0 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Denis** — September 21, 2018 at 10:38 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24033)) + +> Denis says: +> +> update, text appears on real devices, but it’s very very tiny +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Shai Almog** — September 22, 2018 at 6:09 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-23934)) + +> Shai Almog says: +> +> It looks like you used something such as absolute center or flow layout. That won’t work. These layout managers give components their preferred size which means the resizing text will shrink and won’t grow. You need to use a layout that gives out the full width. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Denis** — September 23, 2018 at 9:02 pm ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24070)) + +> Denis says: +> +> yes, you are right, in some parts of UI I used flow layout. Is there any other way to make text bigger on tablets ? because it’s really very very tiny on 10 inch tablets, is it possible to set font size for “Label” UUID (to apply it to all labels at once) depending on device screen size ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Shai Almog** — September 24, 2018 at 4:33 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24082)) + +> Shai Almog says: +> +> You can do that in the theme. See the section in the developer guide about theme layering. You can add a theme on top of the current theme. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Denis** — September 24, 2018 at 6:54 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-23785)) + +> Denis says: +> +> I see, that’s better than maintain different APKs for different devices (phones, tablets), but still needs some logic to figure out on which device app is currently running and there should it load secondary theme or not, is there some handy way ? +> or I just go with one of these +> Display.getInstance().getDeviceDensity() +> Display.getInstance().getDisplayWidth() +> Display.getInstance().getDisplayHeight() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Shai Almog** — September 25, 2018 at 8:23 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24019)) + +> Shai Almog says: +> +> There’s isTablet() both in Display & the CN class. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Denis** — September 25, 2018 at 12:05 pm ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24025)) + +> Denis says: +> +> cool, thanks ! just tried that, interesting, but font changes doesn’t apply, background color does, i.e. I have correct layered theme and code setup, I see different background for tablets, but font size doesn’t change, I am trying t set to “True Type: native:MainRegular” and “True Type Size: Large”, but nothing happens on tablets, I tried both “[Default Style]” and “Label”, “Button” individually, can you please advise ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Denis** — September 26, 2018 at 9:01 pm ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24052)) + +> Denis says: +> +> setting “True Type Size” to millimeters value on component level helped, [Default Style] still doesn’t work even with millimeters value, I set font site for Buttons and Labels, but for example Dialog title is still very tiny, looks like I should set values for all components individually +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Denis** — September 27, 2018 at 8:48 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24084)) + +> Denis says: +> +> also Dialogs for some reason looks differently on mobile and tables, with the same theme (and no layered themes) +> mobile +> [https://uploads.disquscdn.c…]() +> tablet [https://uploads.disquscdn.c…]() +> +> all in simulator haven’t test on real devices yet +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Denis** — September 27, 2018 at 10:43 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-23964)) + +> Denis says: +> +> on real tablet device dialog title appears similar to mobile, but with less spacing from top and bottom +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Shai Almog** — September 28, 2018 at 5:31 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24048)) + +> Shai Almog says: +> +> Which tablet skin? It’s possible the skin is out of date and needs a new theme +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Denis** — September 28, 2018 at 7:17 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-23866)) + +> Denis says: +> +> there are different skins for the same device name, for example for iPad Pro ([ipad-pro.skin]() and [iPadPro.skin]()), iPhoneX (this one is strangest [iPhoneX.skin]() and /[iPhoneX.skin]()) and Galaxy S7 ([GalaxyS7.skin]() and [SamsungGalaxyS7.skin]()), which is a bit confusing, but it would be easier if skins sorted by device name +> +> the skin in above mentioned issue is [IPadPro.skin](), but I have compared to [Nexus5.skin](), different platform, I didn’t though about that, [MicrosoftSurfacePro4.skin]() also have different view of Dialogs, but again it’s another platform, so may there is no issue at all, I have’t real Apple device to compare +> +> p.s. +> I also get these errors when I changing a skin, simulator crashes and I have to start it again, but it works after that +> java.lang.UnsatisfiedLinkError: Native Library C:UsersDenisAppDataLocalTempsqlite-3.7.151-amd64-sqlitejdbc.dll already loaded in another classloader +> java.lang.UnsatisfiedLinkError: org.sqlite.NativeDB._open(Ljava/lang/String;I)V +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Shai Almog** — September 29, 2018 at 4:27 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24069)) + +> Shai Almog says: +> +> Did you refresh theme? It’s a bit hard to guess with that amount of information. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Shai Almog** — September 29, 2018 at 4:31 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24074)) + +> Shai Almog says: +> +> The iPad skin will look like iOS where the dialogs have a different default design inherited from te native theme. +> +> The simulator crash is due to sqlite, we tried multiple ways to workaround it but it seems that the sqlite JDBC support is averse to class loaders. If you use sqlite switching skins will crash and you’ll have to re-run the app. There’s this issue which we tried and failed to fix multiple times [https://github.com/codename…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Shai Almog** — September 30, 2018 at 9:27 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24044)) + +> Shai Almog says: +> +> Default will only work for things that aren’t explicitly defined. Since the title is explicitly defined in the native theme you need to override that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Shai Almog** — September 30, 2018 at 9:28 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-21580)) + +> Shai Almog says: +> +> That mostly relates to the density of the device +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Denis** — October 1, 2018 at 9:07 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-24087)) + +> Denis says: +> +> that makes sense, and I thought the same, the only problem is that we can’t see what defined in native theme ))) I have just 6 items in theme settings, Default style, Button, Container, Label, Multibutton and Toolbar (only Padding/Margin) and as I understand because they are explicitly defined in main theme I have to define them also in layered theme, [Default Style] in layered theme will not override their parameters from main theme, is that correct ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Shai Almog** — October 2, 2018 at 4:49 am ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-23822)) + +> Shai Almog says: +> +> Technically you can open the native theme file from our git repo, but that’s probably not a good idea since that might change. Yes you need to explicitly define things you want to change. E.g. the title in iOS is center aligned and in Android it’s left aligned. We usually don’t override alignment to keep that default behavior. +> The nice thing is that most of these things can be tested live with the simulator and switching is relatively quick (with the exception of the SQLite problem). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + + +### **Denis** — October 2, 2018 at 12:21 pm ([permalink](https://www.codenameone.com/blog/autosizing-add-all-ios-redirects.html#comment-23893)) + +> Denis says: +> +> Thank you Shai, I do exactly the same, use emulator to adjust components, it’s very useful, thanks ! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fautosizing-add-all-ios-redirects.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/avoiding-lists.md b/docs/website/content/blog/avoiding-lists.md new file mode 100644 index 0000000000..3fe8cf8849 --- /dev/null +++ b/docs/website/content/blog/avoiding-lists.md @@ -0,0 +1,389 @@ +--- +title: Avoiding Lists +slug: avoiding-lists +url: /blog/avoiding-lists/ +original_url: https://www.codenameone.com/blog/avoiding-lists.html +aliases: +- /blog/avoiding-lists.html +date: '2016-08-21' +author: Shai Almog +--- + +![Header Image](/blog/avoiding-lists/property-cross-new.jpg) + +When picking up a new UI API people often start with a list of items. Lists are often used for navigation, logic and data so it’s a natural place to start. Codename One’s List class is a bad place to start though…​ It’s complex and encumbered and has far better alternatives. + +### How did we Get Here? + +When we initially created the `List` API we were heavily inspired by Swing’s architecture. The ability to create an infinitely sized list without a performance penalty was attractive and seemed like a good direction for our original 2mb RAM target devices (back in 2006-7). We knew the renderer/model approach was hard for developers to perceive but we also assumed a lot of Swing developers would find it instantly familiar. + +We made attempts to improve `List` in the years since e.g.: `MultiList`, `GenericListCellRenderer`, `ContainerList` etc. + +These helped but the core problems of `List` remain. + +### What Changed? + +Modern interfaces are far more dynamic, we have features such as swipable containers, drag and drop to rearrange etc. The renderer approach complicates trivial tasks e.g.: + + * Variable sized entries – this is impossible in a standard `List` or `MultiList`. We designed `ContainerList` to solve this but it’s both ridiculously inefficient and buggy + + * More than one clickable item per row – it’s common to have more than one item within a row in the `List` that can handle an event. E.g. a delete button. This is a difficult (albeit possible) task for `List` items. + + * Performance – `List` can perform well but writing performant `List` code is a challenge. Anything under 5000 entries would perform better with alternative solutions. If you need more than 5000 rows, reconsider…​ +Scrolling beyond 1000 rows on a mobile device is challenging. + + * Customizability – You can customize the look of the `List` component but there are nuances and some limits. + + * Model – MVC is a good idea but it’s hard. Features like dynamic image download in lists challenge even experienced Codename One developers. + +### What Should we use Instead? + +This varies based on your needs but the general answer is a scrollable `BoxLayout.Y_AXIS` container. + +#### The Simple Use Case + +E.g. if I write a simple `List` such as this: + + + com.codename1.ui.List lst = new com.codename1.ui.List("A", "B", "C"); + lst.addActionListener(e -> Log.p("You picked: " + lst.getSelectedItem())); + +I can convert it to this: + + + String[] abc = new String[] {"A", "B", "C"}; + Container list = new Container(BoxLayout.y()); + list.setScrollableY(true); + for(String s : abc) { + Button b = new Button(s); + list.add(b); + b.addActionListener(e -> Log.p("You picked: " + b.getText())); + } + +Admittedly there is more code in the second version, but it’s far more powerful and as your UI design grows the code will shrink by comparison! + +E.g. if you don’t want the default look of the list or want thumbnail image, or want a single entry to behave differently the latter option is far simpler. + +#### Lead Component + +When you click an entry within the list you can click anywhere and it will work. If you compose an entry in the list from more than one piece those pieces act as one. + +E.g. we have this code in the developer guide section covering `List` renderers: + + + class ContactsRenderer extends Container implements ListCellRenderer { + private Label name = new Label(""); + private Label email = new Label(""); + private Label pic = new Label(""); + private Label focus = new Label(""); + + public ContactsRenderer() { + setLayout(new BorderLayout()); + addComponent(BorderLayout.WEST, pic); + Container cnt = new Container(new BoxLayout(BoxLayout.Y_AXIS)); + name.getAllStyles().setBgTransparency(0); + name.getAllStyles().setFont(Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM)); + email.getAllStyles().setBgTransparency(0); + cnt.addComponent(name); + cnt.addComponent(email); + addComponent(BorderLayout.CENTER, cnt); + + focus.getStyle().setBgTransparency(100); + } + + public Component getListCellRendererComponent(List list, Object value, int index, boolean isSelected) { + Contact person = (Contact) value; + name.setText(person.getName()); + email.setText(person.getEmail()); + pic.setIcon(person.getPic()); + return this; + } + + public Component getListFocusComponent(List list) { + return focus; + } + } + +We can create a similar container using this approach: + + + Container list = new Container(BoxLayout.y()); + list.setScrollableY(true); + for(Contact c : contacts) { + list.add(createContactContainer(c)); + } + + private Container createContactContainer(Contact person) { + Label name = new Label(""); + Label email = new Label(""); + Label pic = new Label(""); + Container cnt = new Container(new BoxLayout(BoxLayout.Y_AXIS)); + name.getAllStyles().setBgTransparency(0); + name.getAllStyles().setFont(Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM)); + email.getAllStyles().setBgTransparency(0); + cnt.add(name); + cnt.add(email); + name.setText(person.getName()); + email.setText(person.getEmail()); + pic.setIcon(person.getPic()); + return BorderLayout.center(cnt). + add(BorderLayout.EAST, pic); + } + +The problem with this approach becomes obvious when we try to add an event listener…​. + +We can make `name` into a `Button` but then what happens when a user clicks `email`? + +We can make all the entries into buttons but that isn’t practical. That’s what [lead component](https://www.codenameone.com/manual/components.html#lead-component-sidebar) is for, we can make one component into a button and it “takes the lead”. If we make name into a button and set it as the lead of the `Container` it will handle all the events and state changes for the entire row! + +__ | For more information on lead components check out [the sidebar](https://www.codenameone.com/manual/components.html#lead-component-sidebar) in the developer guide. +---|--- + +We can change the code above like this and support lead components: + + + private Container createContactContainer(Contact person) { + Button name = new Button("", "Label"); + name.addActionListener(e -> Log.p("You clicked: " + person)); + // ... + Container b = BorderLayout.center(cnt). + add(BorderLayout.EAST, pic); + b.setLeadComponent(name); + return b; + } + +__ | What do you do if you want to exclude an item from the lead component hierarchy (e.g. a delete button)? +Check out [this blog post](/blog/unleading-mutating-accordion.html). +---|--- + +#### Infinite Scroll + +One of our earliest demos showed off a million entries running on a 3mb Nokia mobile phone. While that is an impressive feat it isn’t useful. + +Most real world UI’s use pagination to fetch more data when they reach the bottom of the scroll. This is predictable and easy to integrate both in the client and server code. + +Two classes simplify the process of infinite scrolling list: `InfiniteContainer` and `InfiniteScrollAdapter`. + +`InfiniteContainer` is an easy to use drop-in replacement to `Container`. `InfiniteScrollAdapter` is more versatile, you can apply it to any `Container` including the content pane. We have samples for both [InfiniteContainer](https://www.codenameone.com/javadoc/com/codename1/ui/InfiniteContainer.html) and [InfiniteScrollAdapter](https://www.codenameone.com/javadoc/com/codename1/components/InfiniteScrollAdapter.html) in the JavaDocs. + +### Don’t Use Lists + +In closing I’d like to re-iterate our recommendation: “Don’t use lists”. We didn’t deprecate those API’s because developers rely heavily on them & this might induce “panic”. +There’s no valid reason to use a `List` as opposed to a `Container`. `List` is harder to use, slower & not as flexible. + +We can’t cover every conceivable use case in this post so if you have a `List` or code you can’t imagine any other way, post it in the comments below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — August 22, 2016 at 9:14 pm ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-23004)) + +> bryan says: +> +> Agree with all this. I originally used Lists with custom cell renderers, and with the deprecation of the old GUI builder, I took the opportunity to refactor my code and change all Lists to Containers. Initially my thoughts were “it can’t work as well”, but in fact there appears to be zero performance penalty, and as Shai says, you can create a much better UI experience. Don’t use Lists ! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **Sadart** — August 23, 2016 at 4:31 am ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-22749)) + +> Sadart says: +> +> True. Lists are horrible to deal with. I am still trying to recall when I used them. Stayed away from them years ago because stacking up containers made sense to me. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **Jérémy MARQUER** — August 23, 2016 at 7:35 am ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-22712)) + +> Jérémy MARQUER says: +> +> Totally agree and happy to read this post !! I initially work with complex List but I have refactored it recently. For example, I InfiniteProgress doesn’t animate correctly in items of my List -> I have changed it to InfiniteContainer and it works better !! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **Shai Almog** — August 24, 2016 at 3:58 am ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-23011)) + +> Shai Almog says: +> +> A user posted a question about searching within a list using the filter proxy model. That’s a great question that he seems to have deleted… +> +> The Toolbar JavaDoc contains two samples of searching within a container: [https://www.codenameone.com…]() +> +> Which also shows off animation within the search and quite a few other nice things. Notice that this isn’t demonstrated with an infinite container because searching thru that would require fetching all the data which might not be what you want to do so you will need to adapt the code to work with fetch logic (e.g. special webservice call for search like we do in property cross). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **Carlos** — August 24, 2016 at 8:09 am ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-22937)) + +> Carlos says: +> +> I did not delete the post, I have no idea what happened with it. Anyway, this is the code I posted before (thank you for the samples): +> +> textoFiltro.addDataChangeListener((int type, int index) -> { +> +> filtraProxy(listaRecetas, textoFiltro); +> +> }); +> …….. +> +> private void filtraProxy(final List listaRecetas, TextField textoFiltro) { +> +> Form f = Display.getInstance().getCurrent(); +> +> FilterProxyListModel listaFiltro; +> +> if (listaRecetas.getModel() instanceof FilterProxyListModel) { +> +> listaFiltro = (FilterProxyListModel) listaRecetas.getModel(); +> +> } else { +> +> if(textoFiltro.getText().length() == 0) { +> +> return; +> +> } +> +> listaFiltro = new FilterProxyListModel(listaRecetas.getModel()) { +> +> @Override +> +> protected boolean check(Object o, String str) { +> +> Hashtable h = (Hashtable) o; +> +> Object textoHash = h.get(“Listado”); +> +> return super.check(textoHash, str); +> +> } +> +> }; +> +> listaRecetas.setModel(listaFiltro); +> +> } +> +> if (textoFiltro.getText().length() == 0) { +> +> listaRecetas.setModel(listaFiltro.getUnderlying()); +> +> } else { +> +> listaFiltro.filter(textoFiltro.getText()); +> +> } +> +> f.revalidate(); +> +> } +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **Shai Almog** — August 25, 2016 at 5:21 am ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-21457)) + +> Shai Almog says: +> +> Odd. I’ve seen messages disappear before but I always assumed they were deleted by the asker… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **Jeff Crump** — September 1, 2016 at 5:44 pm ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-22795)) + +> Jeff Crump says: +> +> I would prefer to continue to use the existing List class. When I first started to use Codename One I created an extend List class that utilizes a separate listmodel class, a multi-threaded downloader class, and a renderer class (which generates a prototype). I am able to place buttons, text and other components in the renderer class and have it manage states, mutable backgrounds and pass events to handle unique responses. The downloader class initially pulls two pages of images, then as the list scrolls it downloads additional pages, four at a time, then pauses until the next scroll. The list model class only fires an update when the image is still visible. My ListModel class also implements static filters on the data as the model is instantiated. All of my lists reside on tabs and work/scroll very well. The downloader class uses a two tier thread safe CacheMap. It easily handles 5,000 cells as the cell cache scrolls both directions. It is very fast and doesn’t suffer from pauses or jerky responses. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **Shai Almog** — September 2, 2016 at 5:16 am ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-22880)) + +> Shai Almog says: +> +> That might be one of the rare use cases for which list is indeed still superior. +> +> I think it’s pretty rare because navigating 5000 entries on mobile devices is probably too much for users and obviously the effort you had to put to get it going was pretty big… That’s the gist of this post. Yes there are edge cases that list can handle well but they are edge cases. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **Jeff Crump** — September 2, 2016 at 12:52 pm ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-23039)) + +> Jeff Crump says: +> +> I know, I just didn’t want to lose the existing List component. I wrote most of my code during the first few months after I started using Codename One. It was still very new and I had decided to go with it as is. So I added in what I wanted and worked around the rest. There have been many new components and upgrades since then and it has become a very capable platform. While we have tested very large lists, our target is actually about 500, and with the internal filters the length is between 65 and 85. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **khmaies hassen** — April 20, 2017 at 10:32 pm ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-23227)) + +> khmaies hassen says: +> +> when i reach the end of the list where there are no new pages to show and then i go up and pull the list to refresh, it gives me an empty page. how to reset “pageNumber” to 1 when i use pull to refresh? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **Shai Almog** — April 21, 2017 at 4:44 am ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-23455)) + +> Shai Almog says: +> +> In infinite container? +> +> Place a breakpoint in your callback code and make sure you return the right value on every call +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **khmaies hassen** — April 21, 2017 at 8:58 am ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-21466)) + +> khmaies hassen says: +> +> Even in your example the same thing happenes when you reach the end +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **Shai Almog** — April 22, 2017 at 8:24 am ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-23422)) + +> Shai Almog says: +> +> Which example +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **khmaies hassen** — April 22, 2017 at 12:22 pm ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-23428)) + +> khmaies hassen says: +> +> [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + + +### **Shai Almog** — April 23, 2017 at 5:33 am ([permalink](https://www.codenameone.com/blog/avoiding-lists.html#comment-23521)) + +> Shai Almog says: +> +> I think that’s code that originally relied on InfiniteScrollAdapter which has no pull to refresh or index… You need to use the index value to determine the page you are on with InfiniteContainer +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Favoiding-lists.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/back-vacation.md b/docs/website/content/blog/back-vacation.md new file mode 100644 index 0000000000..f65706e36c --- /dev/null +++ b/docs/website/content/blog/back-vacation.md @@ -0,0 +1,95 @@ +--- +title: We're Back from Vacation +slug: back-vacation +url: /blog/back-vacation/ +original_url: https://www.codenameone.com/blog/back-vacation.html +aliases: +- /blog/back-vacation.html +date: '2019-09-02' +author: Shai Almog +--- + +![Header Image](/blog/back-vacation/new-features-6.jpg) + +Summer is finally over and the kids are going back to school/kindergarten so it’s time to go back to our regularly scheduled posts. I won’t be posting as often as before as I’ll dedicate more time for support/development activities but still there’s a lot to write about…​ + +During our time off we had a lot of changes, I’ll repeat a few big ones which you might have run into already and cover a few that might have gone under the radar. + +### GCM Removal and FCM as Default + +During the month of August Google finally removed their old GCM servers. We’ve prepared for this ages ago but this still took us a bit off guard. We were ready for the switch itself but there were still a couple of things we weren’t prepared for. + +Users who still used the old style of push notifications (prior to the `google-services.json` file approach) had push messages blocked. That was expected. + +__ | You can read about the modern approach to push [here](https://www.codenameone.com/manual/push.html) +---|--- + +Because that no longer works anyway we switched the default build mode to FCM. This solves an issue for developers who neglected to define the `android.messagingService=fcm` build hint (which you no longer need). However, this causes a build error if you don’t have that JSON file in place. You can get this to compile for now by explicitly stating the build hint `android.messagingService=gcm`. However, push won’t work if you do that since the Google run GCM push servers are no longer there. But it will compile which is a start. + +To migrate to the new FCM approach check out the [developer guide section on push](https://www.codenameone.com/manual/push.html). + +### API Level 28 and HTTPS Requirement + +We migrated the build servers to Android API level 28 as required by Google. This migration was a bit painful because Google changed the way clipping works under Android so we had to make some extensive changes to our rendering pipeline. + +However, one thing we can’t mitigate is that Google now blocks HTTP connections (not HTTPS).This is generally a good practice and a requirement on iOS as well. However, if you have an HTTP URL you need to use you can do so with the build hint: + + + android.xapplication_attr=android:usesCleartextTraffic="true" + +### Component Inspector Enhancements + +We implemented a couple of RFEs in the venerable component inspector, specifically [2695](https://github.com/codenameone/CodenameOne/issues/2695) and [1476](https://github.com/codenameone/CodenameOne/issues/1476). + +You can now refresh the component tree and the selection would remain in place but more importantly you can select a component and it will be highlighted in the UI. This is very helpful as a debugging tool. + +![Component inspector highlights current selection](/blog/back-vacation/component-inspector-selection-highlight.png) + +Figure 1. Component inspector highlights current selection + +### AutoCompleteTextComponent and TextComponentPassword + +[Francesco Galgani](https://github.com/jsfan3) contributed an implementation of +[AutoCompleteTextComponent](https://github.com/codenameone/CodenameOne/issues/2705) which allows you to use an auto-complete with the text component framework for a more fluid input UI. + +He also contributed [TextComponentPassword](https://github.com/codenameone/CodenameOne/issues/2654) which is a password field with the same convention. It carries the more modern “show password” icon convention which is far more convenient than the old “double type” approach. + +### Error Callbacks for URLImage + +It’s hard to handle errors in `URLImage` objects. Because they are so “seamless” the point for exception handling is deep withing the class. To solve issue [2703](https://github.com/codenameone/CodenameOne/issues/2703) we had to do something different. + +You can now use the static method `setExceptionHandler` on `URLImage`. It accepts the inner interface `ErrorCallback` which has a single method: + + + public static interface ErrorCallback { + public void onError(URLImage source, Exception err); + } + +So effectively you can do something like this: + + + URLImage.setExceptionHandler((img, err) -> handleError()); + +### So Much More + +I’ll write about other things in the coming weeks as this post is getting a bit long. There’s a lot to cover. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — September 7, 2019 at 7:57 pm ([permalink](https://www.codenameone.com/blog/back-vacation.html#comment-24112)) + +> The Component Inspector enhancements are very helpful! Thank you very much! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fback-vacation.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/background-fetch.md b/docs/website/content/blog/background-fetch.md new file mode 100644 index 0000000000..e15230c4dc --- /dev/null +++ b/docs/website/content/blog/background-fetch.md @@ -0,0 +1,368 @@ +--- +title: Background Fetch +slug: background-fetch +url: /blog/background-fetch/ +original_url: https://www.codenameone.com/blog/background-fetch.html +aliases: +- /blog/background-fetch.html +date: '2016-06-20' +author: Steve Hannah +--- + +![Header Image](/blog/background-fetch/background-fetch.jpg) + +Background fetch allows an app to periodically “fetch” information from the network while the app is in +the background. This is scheduled by the native platform, where apps that support background +fetch will be started up (in the background), and their `performBackgroundFetch` method will be invoked. + +__ | Since the app will be launched directly to the background, you cannot assume that the +`start()` method was invoked prior to the `performBackgroundFetch` call +---|--- + +### Implementing Background Fetch + +Apps that wish to implement background fetch must implement the +[BackgroundFetch](https://www.codenameone.com/javadoc/com/codename1/background/BackgroundFetch.html) +interface in their main class. + +__ | The main class is the one mentioned in the preferences not the state machine or some other class! +---|--- + +On iOS, you also need to include `fetch` in the list of background modes specifically include `fetch` in the +`ios.background_modes` build hint e.g.: + + + ios.background_modes=fetch + +Or for more than one mode: + + + ios.background_modes=fetch,music + +In addition to implementing the `BackgroundFetch` interface, apps must explicitly set the background fetch +interval by invoking `Display.getInstance().setPreferredBackgroundFetchInterval(interval)` at some point, usually +in the `start()` or `init()` method. + +### Platform Support + +Currently background fetch is supported on iOS, Android, and in the Simulator (simulated using timers when the +app is paused). You should use the `Display.getInstance().isBackgroundFetchSupported()` call to check if the +current platform supports it. + +### Sample + +The following code demonstrates simple usage of the API: + + + /** + * A simple demo showing the use of the Background Fetch API. This demo will load + * data from the Slashdot RSS feed while it is in the background. + * + * To test it out, put the app into the background (or select Pause App in the simulator) + * and wait 10 seconds. Then open the app again. You should see that the data is loaded. + */ + public class BackgroundFetchTest implements BackgroundFetch { + + private Form current; + private Resources theme; + List records; + + // Container to hold the list of records. + Container recordsContainer; + + public void init(Object context) { + theme = UIManager.initFirstTheme("/theme"); + + // Enable Toolbar on all Forms by default + Toolbar.setGlobalToolbar(true); + + // Pro only feature, uncomment if you have a pro subscription + // Log.bindCrashProtection(true); + } + + public void start() { + if(current != null){ + // Make sure we update the records as we are coming in from the + // background. + updateRecords(); + current.show(); + return; + } + Display d = Display.getInstance(); + + Form hi = new Form("Background Fetch Demo"); + hi.setLayout(new BoxLayout(BoxLayout.Y_AXIS)); + + Label supported = new Label(); + if (d.isBackgroundFetchSupported()){ + // This call is necessary to initialize background fetch + d.setPreferredBackgroundFetchInterval(10); + + supported.setText("Background Fetch IS Supported"); + } else { + supported.setText("Background Fetch is NOT Supported"); + } + + hi.addComponent(new Label("Records:")); + recordsContainer = new Container(new BoxLayout(BoxLayout.Y_AXIS)); + //recordsContainer.setScrollableY(true); + hi.addComponent(recordsContainer); + + hi.addComponent(supported); + updateRecords(); + hi.show(); + } + + /** + * Update the UI with the records that are currently loaded. + */ + private void updateRecords() { + recordsContainer.removeAll(); + if (records != null) { + for (Map m : records) { + recordsContainer.addComponent(new SpanLabel((String)m.get("title"))); + } + } else { + recordsContainer.addComponent(new SpanLabel("Put the app in the background, wait 10 seconds, then open it again. The app should background fetch some data from the Slashdot RSS feed and show it here.")); + } + if (Display.getInstance().getCurrent() != null) { + Display.getInstance().getCurrent().revalidate(); + } + } + + public void stop() { + current = Display.getInstance().getCurrent(); + if(current instanceof Dialog) { + ((Dialog)current).dispose(); + current = Display.getInstance().getCurrent(); + } + } + + public void destroy() { + } + + /** + * This method will be called in the background by the platform. It will + * load the RSS feed. Note: This only runs when the app is in the background. + * @param deadline + * @param onComplete + */ + @Override + public void performBackgroundFetch(long deadline, Callback onComplete) { + RSSService rss = new RSSService("http://rss.slashdot.org/Slashdot/slashdotMain"); + NetworkManager.getInstance().addToQueueAndWait(rss); + records = rss.getResults(); + System.out.println(records); + onComplete.onSucess(Boolean.TRUE); + + } + } +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Nick Koirala** — June 22, 2016 at 5:13 am ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-21454)) + +> Nick Koirala says: +> +> Just tried this out on Android. +> +> It looks good, and I was pleased to see that I can schedule a local notification from the backgroundFetch, so if there is a reason for the user to open the app based on the background fetch it is possible. +> +> I’ve found that you can’t poll faster than 60 seconds, not a big problem, an update every minute is still plenty, but might be worth noting as the example code uses 10 seconds, but that’s not what result I’m getting on my phone. If you set it lower then it’ll just call the method every 60 seconds. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Lukman Javalove Idealist Jaji** — June 23, 2016 at 9:00 am ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-22912)) + +> Lukman Javalove Idealist Jaji says: +> +> Will it be a good programming practice to use this feature to connect to a remote DB every x minutes? Or is there a more effective way to achieve this? Sometimes when the back button is pressed on the MainForm, the app ought to be minmized but when I reopen, it looks like the app starts all over again. Does this feature prevent that? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Shai Almog** — June 24, 2016 at 6:24 am ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-22748)) + +> Shai Almog says: +> +> Probably not, it will grind your battery down to nothing. The right thing to do is to use push to trigger an update. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Lukman Javalove Idealist Jaji** — June 26, 2016 at 6:36 am ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-22813)) + +> Lukman Javalove Idealist Jaji says: +> +> Thanks Shai .. does this apply also to on device background checks … say if a file exists in storage or on the filesystem +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Shai Almog** — June 27, 2016 at 3:04 am ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-22724)) + +> Shai Almog says: +> +> I have no idea. I’m guessing it should work. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Scott Turner** — May 11, 2017 at 2:21 pm ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-23401)) + +> Scott Turner says: +> +> I noticed an issue with the BackgroundFetch functionality. It’s not mentioned in this blog post, but for ios, you have to set ios.locationusagedescription in the build hints, otherwise it won’t hit the performBackgroundFetch callback on apple devices. It took me several hours of poking around to figure this out, so it’s definitely worth amending the post. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Shai Almog** — May 12, 2017 at 12:25 pm ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-23533)) + +> Shai Almog says: +> +> I’m not familiar enough with that piece of code so I asked about it. I understand that there should be no dependency on location usage description so if this happens with a simple hello world that might be a bug. One thing I did understand is that iOS is ridiculously sensitive about background behavior. So if you use things like location etc. this might fail by crashing with no messages or any indication of what went wrong. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Scott Turner** — May 12, 2017 at 12:48 pm ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-23333)) + +> Scott Turner says: +> +> Thanks, Shai. After playing around with BackgroundFetch I realized it wasn’t really right for my use case anyway. It’s far too unpredictable on ios. I need it to hit reliably at least once every 30 seconds and it seems like it doesn’t allow that sort of flexibility. Oh well! Thanks for the follow up. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Ch Hjelm** — May 20, 2019 at 8:28 pm ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-24093)) + +> Ch Hjelm says: +> +> I understand that only `init()` will be executed before `performBackgroundFetch` is run in the background. If I have a lot of things being executed on a normal application startup (and which are not necessary for the `performBackgroundFetch` to execute), I guess that initialization code should then rather go into `start()` to avoid slowing the `performBackgroundFetch` down (with the risk that it takes too long and get killed). In which case, `start()` should test on whether current is null like in your example, and only execute all the initialization code if `current` actually is null. Would you agree this is the best approach? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Shai Almog** — May 21, 2019 at 4:26 am ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-23991)) + +> Shai Almog says: +> +> This is standard Codename One code that has nothing to do with suspend resume. I suggest checking out the second chapter of the uber book available for free here: [https://uber.cn1.co/]() look for the part about application lifecycle. +> +> init is only invoked when the app is launched from destroyed mode (cold start). Start is invoked on resume from suspended mode. This lets us detect a case of resume which might be applicable. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Ch Hjelm** — May 21, 2019 at 6:42 am ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-24058)) + +> Ch Hjelm says: +> +> Thanks. I already understand the life cycle (and I have your book :-)) and my question IS specific to background fetch. To rephrase: today I have a lot of heavy initialization in init() which is only needed if a *user* cold-starts the app but *not* necessary if the app is cold-started just to run the `performBackgroundFetch` . If all that initialization code is run on every background fetch it may slow down the fetch and the app may get killed, or at least it will consume unnecessary battery. So, I just wanted to double check if it is a good/workable approach to move the heavy initialization into `start()` using the pattern shown below? +> `start() { +> if (current!=null) { +> current.show(); +> return; +> } else { +> //heavy initialization normally placed in init(), only needed for user but not necessary for background fetch +> } +> //normal start code… +> }` +> Hope I managed to make it clear. I basically want to double check with your expertise because any issues here could be difficult to catch in the Simulator or in device testing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Shai Almog** — May 22, 2019 at 9:33 am ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-23998)) + +> Shai Almog says: +> +> You shouldn’t write any code there. It could slow down restore and you should minimize code in init as they can trigger ANR’s (app not responding). In a case of ANR your app could be killed instantly. You can start a thread in the init code and do initialization logic there after a small delay to let the UI grab some CPU. There is no reason to prefer start over init() for this sort of logic though. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Arthur Major** — July 23, 2021 at 4:42 pm ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-24470)) + +> Arthur Major says: +> +> I tested this code and works good in Android 7 and below, but Android 8+ just run once, is there something else I have to do? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Steve Hannah** — July 23, 2021 at 5:04 pm ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-24471)) + +> Steve Hannah says: +> +> Background execution has gotten a lot harder with newer versions of Android. It is difficult to predict when the platform will run your background tasks, and they may be blocked for any reason on both Android and iOS. If you can check the device log it might give you a clue as to what its “complaint” is. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Arthur Major** — July 23, 2021 at 11:57 pm ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-24472)) + +> Arthur Major says: +> +> 2021-07-23 17:25:42.650 8479-8479/? D/ViewRootImpl@984f7f7[SigueloNotifAppStub]: setView = DecorView@bbbdd82[SigueloNotifAppStub] TM=true MM=false +> 2021-07-23 17:25:42.651 8479-8479/? D/ViewRootImpl@984f7f7[SigueloNotifAppStub]: dispatchAttachedToWindow +> 2021-07-23 17:25:42.677 8479-8479/? D/ViewRootImpl@984f7f7[SigueloNotifAppStub]: Relayout returned: old=[0,0][0,0] new=[0,0][1080,1920] result=0x7 surface={valid=true 535584559104} changed=true +> 2021-07-23 17:25:42.721 8479-8479/? D/ViewRootImpl@984f7f7[SigueloNotifAppStub]: MSG_RESIZED_REPORT: frame=Rect(0, 0 – 1080, 1920) ci=Rect(0, 72 – 0, 0) vi=Rect(0, 72 – 0, 0) or=1 +> 2021-07-23 17:25:42.721 8479-8479/? D/ViewRootImpl@984f7f7[SigueloNotifAppStub]: MSG_WINDOW_FOCUS_CHANGED 1 +> 2021-07-23 17:25:48.534 8479-8479/? D/ViewRootImpl@984f7f7[SigueloNotifAppStub]: MSG_WINDOW_FOCUS_CHANGED 0 +> 2021-07-23 17:25:48.603 8479-8479/? D/ViewRootImpl@984f7f7[SigueloNotifAppStub]: Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x5 surface={valid=false 0} changed=true +> 2021-07-23 17:25:48.650 8479-8479/? D/ViewRootImpl@984f7f7[SigueloNotifAppStub]: Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x1 surface={valid=false 0} changed=false +> 2021-07-23 17:25:53.304 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: setView = DecorView@bbbdd82[SigueloNotifAppStub] TM=true MM=false +> 2021-07-23 17:25:53.313 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: dispatchAttachedToWindow +> 2021-07-23 17:25:53.346 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: Relayout returned: old=[0,0][0,0] new=[0,0][1080,1920] result=0x7 surface={valid=true 535584444416} changed=true +> 2021-07-23 17:25:53.385 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: MSG_RESIZED_REPORT: frame=Rect(0, 0 – 1080, 1920) ci=Rect(0, 72 – 0, 0) vi=Rect(0, 72 – 0, 0) or=1 +> 2021-07-23 17:25:53.385 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: MSG_WINDOW_FOCUS_CHANGED 1 +> 2021-07-23 17:25:58.730 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: MSG_WINDOW_FOCUS_CHANGED 0 +> 2021-07-23 17:25:58.775 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x5 surface={valid=false 0} changed=true +> 2021-07-23 17:25:58.884 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x1 surface={valid=false 0} changed=false +> 2021-07-23 17:27:39.347 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x1 surface={valid=false 0} changed=false +> 2021-07-23 17:27:39.394 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x7 surface={valid=true 535346876416} changed=true +> 2021-07-23 17:27:39.409 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: MSG_WINDOW_FOCUS_CHANGED 1 +> 2021-07-23 17:27:43.525 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: MSG_WINDOW_FOCUS_CHANGED 0 +> 2021-07-23 17:27:43.596 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x5 surface={valid=false 0} changed=true +> 2021-07-23 17:27:43.677 8668-8668/? D/ViewRootImpl@de60cd[SigueloNotifAppStub]: Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x1 surface={valid=false 0} changed=false +> +> That’s all the log I got when it runs. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Steve Hannah** — July 28, 2021 at 12:54 pm ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-24473)) + +> Steve Hannah says: +> +> I’ve done some digging on this, and believe I have found the issue. (described here ). +> +> “Prior to Android 8.0, the usual way to create a foreground service was to create a background service, then promote that service to the foreground. With Android 8.0, there is a complication; the system doesn’t allow a background app to create a background service. For this reason, Android 8.0 introduces the new method startForegroundService() to start a new service in the foreground. After the system has created the service, the app has five seconds to call the service’s startForeground() method to show the new service’s user-visible notification. If the app does not call startForeground() within the time limit, the system stops the service and declares the app to be ANR.” +> +> This doesn’t offer a clear solution at your level, unfortunately, other than attempting to keep execution of background fetches under 5 seconds — it isn’t clear whether that is a solution or not. +> +> Working around these growing background execution restrictions is tricky. We may end up deprecating some of these background execution APIs and shifting to implementing this type of thing in cn1libs. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbackground-fetch.html) + + +### **Arthur Major** — July 28, 2021 at 4:44 pm ([permalink](https://www.codenameone.com/blog/background-fetch.html#comment-24474)) + +> Arthur Major says: +> +> Thanks for your response, so i think in this case is better continue with a native solution. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/badges.md b/docs/website/content/blog/badges.md new file mode 100644 index 0000000000..3e68717680 --- /dev/null +++ b/docs/website/content/blog/badges.md @@ -0,0 +1,109 @@ +--- +title: Badges +slug: badges +url: /blog/badges/ +original_url: https://www.codenameone.com/blog/badges.html +aliases: +- /blog/badges.html +date: '2014-05-13' +author: Shai Almog +--- + +![Header Image](/blog/badges/badges-1.png) + + + + + +![Picture](/blog/badges/badges-1.png) + + + + +iOS allows us to send a push notification to trigger a numeric badge on the application icon, this is something you could do with Codename One for quite some time although it was mostly undocumented. You could send a push notification with the type 100 and the number for the badge and that number would appear on the icon, when you launch the app the next time the default behavior is to clear the badge value. + + + + +There is also an option to send push type 101 and provide a badge number semi-colon and a message e.g. use a message body such as this: “3;This message is shown to the user with number 3 badge”. Obviously, this feature will only work for iOS so don’t send these push types to other platforms… + + + + + +In addition to that we have added an option to change the badge number, this is useful if you want the badge to represent the unread count within your application. To do this we added two methods to display: isBadgingSupported() & setBadgeNumber. + + +Notice that even if isBadgingSupported will return true, it will not work unless you activate push support! + + + + + +To truly utilize this you might need to disable the clearing of the badges on startup which you can do with the build argument ios.enableBadgeClear=false + + + + +On a separate note we also added the ability to scale images based on aspect ratio + + +to the ImageIO class with a new method saveAndKeepAspect which should provide more memory efficient scaling. This is important for Android which manages image memory quite poorly. + + + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — September 4, 2014 at 7:13 am ([permalink](https://www.codenameone.com/blog/badges.html#comment-22029)) + +> Anonymous says: +> +> I’ve made a mistake in this post. Number badges should be separated by a space not a semicolon so this “3;This message is shown to the user with number 3 badge” should be really: +> +> “3 This message is shown to the user with number 3 badge” +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbadges.html) + + +### **Omar Suleiman** — January 14, 2018 at 12:42 pm ([permalink](https://www.codenameone.com/blog/badges.html#comment-24155)) + +> Omar Suleiman says: +> +> We tried more time to find badges with android but as some comments in stackoverflow is only working on IOS, so when will it become available on android? . +> +> Thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbadges.html) + + +### **Shai Almog** — January 15, 2018 at 6:45 am ([permalink](https://www.codenameone.com/blog/badges.html#comment-23742)) + +> Shai Almog says: +> +> Hi, +> I’ve answered this here: [https://stackoverflow.com/q…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbadges.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/badging-arbitrary-components.md b/docs/website/content/blog/badging-arbitrary-components.md new file mode 100644 index 0000000000..f211a1b884 --- /dev/null +++ b/docs/website/content/blog/badging-arbitrary-components.md @@ -0,0 +1,85 @@ +--- +title: Badging Arbitrary Components +slug: badging-arbitrary-components +url: /blog/badging-arbitrary-components/ +original_url: https://www.codenameone.com/blog/badging-arbitrary-components.html +aliases: +- /blog/badging-arbitrary-components.html +date: '2016-11-02' +author: Shai Almog +--- + +![Header Image](/blog/badging-arbitrary-components/badge-floating-button.png) + +Last week a question came up in [stackoverflow](http://stackoverflow.com/questions/40256864/how-to-create-facebook-like-notification-badges-in-codenameone) +that came out quite a few times before but this time I had a better answer thanks to the round border. After giving +that answer I recalled that I already wrote some code to implement badging in the [FloatingActionButton](/blog/floating-button.html) +but never exposed it because of some bugs…​ + +So I took the time and looked at the bugs in that code, turns out it was pretty trivial to fix so the same sample +I gave for stackoverflow can now look like this: + + + Form hi = new Form("Badge"); + + Button chat = new Button(""); + FontImage.setMaterialIcon(chat, FontImage.MATERIAL_CHAT, 7); + + FloatingActionButton badge = FloatingActionButton.createBadge("33"); + hi.add(badge.bindFabToContainer(chat, Component.RIGHT, Component.TOP)); + + TextField changeBadgeValue = new TextField("33"); + changeBadgeValue.addDataChangedListener((i, ii) -> { + badge.setText(changeBadgeValue.getText()); + badge.getParent().revalidate(); + }); + hi.add(changeBadgeValue); + + hi.show(); + +That’s shorter (mostly because of default styles) and pretty neat in general. It results in this: + +![Badge floating button in action](/blog/badging-arbitrary-components/badge-floating-button.png) + +Figure 1. Badge floating button in action + +Ideally I’d like to continue this trend into validators and other builtin tools to use more of the builtin borders and +material icons. This is something we need to work on more as we move forward. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **João Bastos** — November 3, 2016 at 8:47 am ([permalink](https://www.codenameone.com/blog/badging-arbitrary-components.html#comment-22949)) + +> createBadge error. Is it missing “public” statement in the method? or i´m missing something here? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbadging-arbitrary-components.html) + + +### **Shai Almog** — November 4, 2016 at 5:47 am ([permalink](https://www.codenameone.com/blog/badging-arbitrary-components.html#comment-22930)) + +> Shai Almog says: +> +> Sorry, I neglected to mention that this is landing in the Friday release today so when you get a new update the code should compile fine. You can use Update Client Libraries later today to get the update. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbadging-arbitrary-components.html) + + +### **João Bastos** — November 4, 2016 at 8:43 am ([permalink](https://www.codenameone.com/blog/badging-arbitrary-components.html#comment-23013)) + +> João Bastos says: +> +> Ok. Thanks Shai +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbadging-arbitrary-components.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/beating-the-arc.md b/docs/website/content/blog/beating-the-arc.md new file mode 100644 index 0000000000..727ea917d2 --- /dev/null +++ b/docs/website/content/blog/beating-the-arc.md @@ -0,0 +1,61 @@ +--- +title: Beating The ARC +slug: beating-the-arc +url: /blog/beating-the-arc/ +original_url: https://www.codenameone.com/blog/beating-the-arc.html +aliases: +- /blog/beating-the-arc.html +date: '2014-05-06' +author: Shai Almog +--- + +![Header Image](/blog/beating-the-arc/beating-the-arc-1.png) + + + + + +![Picture](/blog/beating-the-arc/beating-the-arc-1.png) + + + + +For the uninitiated, ARC is Apple’s term for Automatic Reference Counting. Objective-C uses a reference counting scenario to collect objects which is pretty painful to work with. Personally I preferred C/C++’s manual delete/free to the Objective-C semantics. But a couple of years ago Apple introduced ARC in which the compiler implicitly inserts the retain/release reference counting logic. + +While its a big improvement its still a reference counter with many of the implied limitations. It solves 95% of your memory handling logic leaving the hardest 5% for you to deal with manually but it does have one advantage over a GC: determinism. Since memory is deallocated immediately it provides consistent performance with no GC stalls. + +We briefly covered the garbage collection approach we took with the new iOS VM, however this time we’ll go more in-depth into the implementation details. Our goal with the garbage collection was not to create the fastest GC possible but the one that stalls the least. Up to now pretty much all open source/iOS VM’s used Boehm GC which is a conservative GC designed for C, it is state of the art and pretty cool but stalls. + +Boehm can’t really avoid stalling since it needs to stop all executing threads so it can traverse their stacks and this takes time… + +Unlike C, we can make a lot of assumptions in a Java application thanks to the type safety and clearly defined VM. This makes the process of collecting comparatively easy and makes it possible to collect without stopping the world. We do however need that threads yield the CPU shortly otherwise the GC will be blocked, this is generally a good practice and the EDT makes sure to follow that practice however if you do something like this: + +while(true) { + +System.out.println(‘WHeee”); + +} + +It would block our new GC from running unless you add a Thread.yield/sleep or wait() call (besides draining the CPU/battery). This might be considered a flaw but we mitigated that to some degree by incorporating a reference counting collector as well (similar to ARC) which deals with the “low hanging garbage” thus making the actual GC process far less important so our GC sweeps don’t need to be very fast. + +But this post is titled “beating the ARC”… How can we be faster than ARC? + +Simple, we don’t de-allocate. All objects that our reference counter deems to be garbage are sent to the garbage heap and finalized/deleted on the GC thread (as is custom in Java) hence we get the benefit of multi-core parallel cleanup logic on top of the fast performance. + +Our GC never actually pauses the world, it uses a simple mark sweep cycle where we iterate the thread stacks and mark all objects in use, we then iterate all the objects in the world and delete the living, unmarked objects. Since deletion of GC’d and reference counted objects is always done in the GC thread this is pretty easy and thread safe on the VM part. The architecture is actually rather simple and conservative. + +The benefit of the reference counting approach becomes very clear with the non-pausing GC, since the reference counting system still kicks out objects from RAM the GC serves only for the heavy lifting. So it can be executed less frequently and its OK for it to miss quite a few objects as the reference counting implementation will pick up the slack. + +We are still working on getting this into users hands ideally within the next couple of weeks (albeit in alpha state) and eventually open sourcing all of that code. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/better-error-logging.md b/docs/website/content/blog/better-error-logging.md new file mode 100644 index 0000000000..a7a20a9a18 --- /dev/null +++ b/docs/website/content/blog/better-error-logging.md @@ -0,0 +1,125 @@ +--- +title: Better Error Logging +slug: better-error-logging +url: /blog/better-error-logging/ +original_url: https://www.codenameone.com/blog/better-error-logging.html +aliases: +- /blog/better-error-logging.html +date: '2019-04-15' +author: Shai Almog +--- + +![Header Image](/blog/better-error-logging/debugging.jpg) + +A common pain point in most GUI frameworks is the hidden stack traces. When we have an app in production we get occasional emails from crash protection which are cryptic and hard to figure out. They usually start with the EDT loop and make no sense. + +The reason for that is `callSerially()`. When we have code that invokes `callSerially` we essentially lose the previous stack trace. So your stack trace would look roughly like this: + + + java.lang.RuntimeException: + at com.mycompany.MyClass.myMethod(MyClass.java:400) + at com.codename1.ui.Display.edtLoopImpl(Display.java:1166) + at com.codename1.ui.Display.mainEDTLoop(Display.java:1070) + at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120) + at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176) + +For most cases you can just fix line 400 of `MyClass` so it won’t throw an exception but you might be hiding a worse bug. Lets say that line fails because it expects a specific condition to exist in the app and that condition isn’t met. A good example for this would be logged in users. Lets say your app expects the user to be logged in before `myMethod` is invoked but for some reason he isn’t. + +That means the real bug occurred elsewhere probably in the area of code where `callSerially() → myClass.myMethod(;` was called. Lets say you looked over the entire body of code and you have suspects but can’t tell which part is at fault. Narrowing this down would help…​ + +That’s where `Display.setEnableAsyncStackTraces()` comes in. When set to true it creates a “fake” exception for every `callSerially` if there’s a “real” exception thrown within the `callSerially` it uses this “fake” one as the cause. That means you will be able to see the cause for a specific bug when this is enabled. + +Notice that this API is potentially prohibitive in terms of performance. As such we recommend that people don’t turn this on by default. You can include this as a user configuration or use it in debug builds. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — April 17, 2019 at 3:10 pm ([permalink](https://www.codenameone.com/blog/better-error-logging.html#comment-23990)) + +> Francesco Galgani says: +> +> In the Javadoc of `Display.getInstance().setEnableAsyncStackTraces(…);`, it’s written: «Currently this is only supported in the JavaSE/Simulator port». Is it true? In that case, it’s not useful for crash reports… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-error-logging.html) + + +### **Shai Almog** — April 18, 2019 at 2:43 am ([permalink](https://www.codenameone.com/blog/better-error-logging.html#comment-24057)) + +> Shai Almog says: +> +> It should work for desktop builds and Android as far as the code goes. Some platforms might fail because of the way stack traces are handled but I don’t see anything in the code that indicates this was actually enforced. It might not work everywhere e.g. on iOS. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-error-logging.html) + + +### **Francesco Galgani** — April 23, 2019 at 1:58 pm ([permalink](https://www.codenameone.com/blog/better-error-logging.html#comment-24108)) + +> Francesco Galgani says: +> +> There is something strange, maybe you can help me to better understand the logic of setEnableAsyncStackTraces. Without setEnableAsyncStackTraces, I have a NullPointerException without any indication of the line of code that thrown the exception (so the log is useless), while with setEnableAsyncStackTraces(true) I have a com.codename1.ui.Display$EdtException, but in the log there is no mention of any NullPointerException, so it’s unclear where is the exception and why is there an exception. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-error-logging.html) + + +### **Francesco Galgani** — April 23, 2019 at 2:21 pm ([permalink](https://www.codenameone.com/blog/better-error-logging.html#comment-24096)) + +> Francesco Galgani says: +> +> I identified the cause of this exception, it was a popup.remove() (note +> that “popup” and its parent weren’t null), however the solution that I +> found is to use removeComponent (from the parent of the parent) instead +> of popup.remove(). It’s unclear to me the logic of this exception, +> however my question is the same: why does a NullPointerException become a +> Display$EdtException using setEnableAsyncStackTraces? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-error-logging.html) + + +### **Shai Almog** — April 23, 2019 at 4:55 pm ([permalink](https://www.codenameone.com/blog/better-error-logging.html#comment-24115)) + +> Shai Almog says: +> +> This sounds like a bug in Codename One that triggered a cascading error. +> +> What’s popup? What type of component is it? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-error-logging.html) + + +### **Francesco Galgani** — April 23, 2019 at 5:57 pm ([permalink](https://www.codenameone.com/blog/better-error-logging.html#comment-23921)) + +> Francesco Galgani says: +> +> This is the code: [https://gist.github.com/jsf…]() +> As you can see, I’m trying to adapt AutoCompleteTextField to my needs. Note at the bottom of the code the commented popup.remove(). I’m trying to close the popup list immediately when setEditable(false) is called. A safe and correct way to do it could fit with my use case, but maybe my code is not safe. Moreover, calling setEditable(true) after setEditable(false) causes that the popup list will not appear again when the user start typing in the field. I hope that few changes can fix this code. Do you have any suggestion? (I know that Stack Overflow is more suitable for this type of questions, however we started the discussion here. Thank you for your support) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-error-logging.html) + + +### **Shai Almog** — April 24, 2019 at 4:04 am ([permalink](https://www.codenameone.com/blog/better-error-logging.html#comment-24040)) + +> Shai Almog says: +> +> Maybe this is related to an ongoing animation which triggered this. That might explain the broken stack trace. It might be necessary to flush animations first for this method to work. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-error-logging.html) + + +### **Francesco Galgani** — April 24, 2019 at 6:20 am ([permalink](https://www.codenameone.com/blog/better-error-logging.html#comment-24066)) + +> Francesco Galgani says: +> +> You’re right!!! Thank you! You gave me the right hint to solve half of this issue: the first half is what you supposed (that solved the issue in several cases), the second half was that an override of initComponent() and deinitalize() allowed me to solve the exception in other cases. This is my fixed code: [https://gist.github.com/jsf…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-error-logging.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/better-logging.md b/docs/website/content/blog/better-logging.md new file mode 100644 index 0000000000..ea2ddf6d2e --- /dev/null +++ b/docs/website/content/blog/better-logging.md @@ -0,0 +1,96 @@ +--- +title: Better Logging +slug: better-logging +url: /blog/better-logging/ +original_url: https://www.codenameone.com/blog/better-logging.html +aliases: +- /blog/better-logging.html +date: '2017-03-06' +author: Shai Almog +--- + +![Header Image](/blog/better-logging/new-features-1.jpg) + +I didn’t post much about new features in a while because we’ve been so busy with the bootcamp that we didn’t have as much time to write the posts or the actual functionality. But a few features/changes did slide in over the past couple of weeks as is pretty much inevitable. + +There are a lot of small changes so I’ll divide them to avoid confusion. + +### JSObject toString + +Up until now if you got a callback or had obtained a [JSObject](https://www.codenameone.com/javadoc/com/codename1/javascript/JSObject.html) and wanted to know what it contained e.g. via: + + + Log.p("My JSObject is: " + myJSObject); + +You would get the default `toString()` behavior which would give you no helpful information other than a unique object id. This is silly since JavaScript has a `toString()` method and what you probably want is to call that. So now the `toString()` method implicitly calls the JavaScript `toString()` method thus providing you with useful information for debugging. + +### Crash Logs + +`Log.e(exception)` prints the stack trace exception into the logs which you can view from the device using crash protection. This isn’t new functionality. However, when we launched Codename One we were very concerned with app size and tried to remove inter-dependencies so we didn’t use the `Log` class in many places. + +As a result our code was littered with `printStackTrace()` calls which might make some on-device failures much harder to investigate especially for iOS. We replaced almost all of those legacy usages with proper `Log.e()` calls so it’s possible that some of the crash reports you will get in the future will include new information. + +### Universal Windows Platform & Desktop Done Listener + +I wasn’t even aware this didn’t work in UWP but it seems that the done listener wasn’t implemented there. + +For those of you who don’t know, text field supports a special listener mode that allows you to bind a done listener such as: + + + tf.setDoneListener(e -> done()); + +This happens when the user presses the done button in the virtual keyboard to perform the action. So you can use that to trigger an action immediately without requiring the user to press another button. + +The other day Steve also added this to the JavaSE port which means you should be able to debug the done listener in the simulator too. + +### Include Nulls + +I mentioned this [pull request](https://github.com/codenameone/CodenameOne/pull/2051) from [Terry Wilkinson](https://github.com/twilkinson) in the Friday blog post but I didn’t go into details. + +This pull request adds a mode to the `JSONParser` where null attributes will still be included in the `keySet` of the parse `Map`. So you should be able to do something like this: + + + JSONParser p = new JSONParser(); + p.setIncludeNulls(true); + Map m = p.parseJSON(reader); + for(String key : m.keySet()) { + Object value = m.get(key); + // here value might be null where in the past a null value was just omitted + } + +Now why would you need that? + +Lets say you display the set of attributes for a user to edit: + + + Given Name: Shai + Surname: Almog + Age: null + +I didn’t specify the age but in the old parser age would be removed so I wouldn’t know how to add it. This works OK if you know the keys in advance but obviously this isn’t as flexible. + +### Localizable SignatureComponent: + +Last but not least Steve added the ability to localize the signature component by setting some values in the resource bundle. You can learn more about resource bundles and localization [here](https://www.codenameone.com/how-do-i---localizetranslate-my-application-apply-i18nl10n-internationalizationlocalization-to-my-app.html). + +You can use the following keys when localizing: + +Table 1. Resource Bundle keys Key | Default Value +---|--- +`SignatureComponent.LeadText` | Press to sign +`SignatureComponent.DialogTitle` | Sign Here +`SignatureComponent.LeadText` | Press to sign +`SignatureComponent.SaveButtonLabel` | Save +`SignatureComponent.ResetButtonLabel | Reset +`SignatureComponent.CancelButtonLabel | Cancel +`SignatureComponent.ErrorDialog.SignatureRequired.Title` | Signature Required +`SignatureComponent.ErrorDialog.SignatureRequired.Body` | Please draw your signature in the space provided. +`SignatureComponent.ErrorDialog.OK` | OK + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/better-vscode-support-for-maven-projects.md b/docs/website/content/blog/better-vscode-support-for-maven-projects.md new file mode 100644 index 0000000000..e958b0a85f --- /dev/null +++ b/docs/website/content/blog/better-vscode-support-for-maven-projects.md @@ -0,0 +1,166 @@ +--- +title: Better VSCode Support for Maven Projects +slug: better-vscode-support-for-maven-projects +url: /blog/better-vscode-support-for-maven-projects/ +original_url: https://www.codenameone.com/blog/better-vscode-support-for-maven-projects.html +aliases: +- /blog/better-vscode-support-for-maven-projects.html +date: '2022-03-11' +author: Steve Hannah +description: Our next update to the Codename One application archetype (7.0.59) includes + some VSCode-specific config files to help improve integration for Maven Projects. +--- + +Our next update to the Codename One application archetype (7.0.59) includes some VSCode-specific config files to help improve integration for Maven Projects. + +![VSCode configs - Codename One](/blog/better-vscode-support-for-maven-projects/VSCode-configs-Codename-One-1024x536.jpg) + +Switching to Maven has been a good thing over all. Maven’s dependency management allows projects to work more consistently out of the box. No more missing dependencies, for the most part. Just clone the repo, build the project and go. + +Maven’s dependency management and standard project structure results in one standard project structure that should work in any IDE that supports Maven. Unfortunately, each IDE still requires a little bit of fine-tuning to wire up our Maven goals to the IDEs’ menus. + +For the initial transition, we focused most of our attention on the experience in IntelliJ and NetBeans. **IntelliJ**, because it is the most widely used, and **NetBeans**, because it provides (arguably) the best Maven integration, and therefore, didn’t require us to do very much. + +We did our best with Eclipse, but will need to take a second pass at it, as it uses a very different model for its launch actions than NetBeans and IntelliJ. + +We left VSCode users on their own to do the link-ups, for the most part, because they’re such a clever bunch, and we knew they’d be able to figure it out 🙂 + +Now that the dust has settled on the migration, we’re circling back to try to tighten it up. Our next update to the Codename One application archetype (7.0.59) includes some VSCode-specific config files to help improve integration. + +### Opening Projects in VSCode + +I’ll demonstrate this integration by creating a new Codename One Application project in [Codename One initializr](https://start.codenameone.com/). + +Point your browser to **[https://start.codenameone.com](https://start.codenameone.com/)** + +![](/blog/better-vscode-support-for-maven-projects/start-codenameone-com.png) + +In the left panel, select the “Bare-bones Java App” template, enter a package and Main Class, and select “VSCode” in the **IDE** drop-down. Then press the **Download** button. + +It will prompt you to save the project, which will then download as a zip file. Extract the zip file, then open the resulting project folder in VSCode. + +The project window should look like the following screenshot: + +![](/blog/better-vscode-support-for-maven-projects/vscode-window.png) + +## NOTE + +> You may be prompted to install the Java Extension Pack in one of the notices in the lower-right corner. If so, you should follow these prompts to install that extension. + +### Running the Project + +Unfortunately VSCode “Run” button doesn’t work to run the project in the simulator. We’re working on that. To run the project in the Codename One simulator, you’ll need to use the “Run in Simulator” command which is available in the **Maven favorites** menu. + +In the left “Explorer” panel, you should see a “Maven” option at the bottom. Expand this to show all of the modules in the application. The first module listed is the “root” module, and is also the module on which all of the core actions are registered. + +Right click on this module, then select “Favorites…​” in the context menu as shown below: + +![](/blog/better-vscode-support-for-maven-projects/maven-favorites.png) + +This will reveal a menu with all of the important actions you’ll need to perform on your project. + +![](/blog/better-vscode-support-for-maven-projects/favorites-menu.png) + +## IMPORTANT + +> If this is your first time running the project, you should select "Tools > Update Codename One" to force the project to download all of the dependencies. If you don’t do this, it is possible you’ll get an error when you try to run the app, due to missing dependencies. + +Select the “Run in Simulator” option to build and launch your app in the Codename One simulator. + +![](/blog/better-vscode-support-for-maven-projects/hello-simulator.png) + +### Still Work To Do + +Currently, debugging is still a bit of a challenge in VSCode. We are working on improving that process, and should have that sorted out soon. If you use VSCode, please let us know what you think, on one of our channels: [Reddit](https://www.reddit.com/r/cn1/), [StackOverflow](https://stackoverflow.com/questions/tagged/codenameone), the mailing list, or in the comment section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved here for historical context. New discussion happens in the Discussion section below._ + + +### **Bryan Buchanan** — June 7, 2022 at 11:22 am ([permalink](https://www.codenameone.com/blog/better-vscode-support-for-maven-projects.html#comment-24536)) + +> Bryan Buchanan says: +> +> Trying this out. Followed all the steps, and get to +> If this is your first time running the project, you should select “Tools > Update Codename One” to force the project to download all of the dependencies +> +> Under Tools there is no Update option ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-vscode-support-for-maven-projects.html) + + +### **Bryan Buchanan** — June 9, 2022 at 12:50 am ([permalink](https://www.codenameone.com/blog/better-vscode-support-for-maven-projects.html#comment-24537)) + +> Bryan Buchanan says: +> +> Oops – was looking at the wrong Tools location. All good now ! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-vscode-support-for-maven-projects.html) + + +### **Bryan Buchanan** — June 10, 2022 at 7:53 am ([permalink](https://www.codenameone.com/blog/better-vscode-support-for-maven-projects.html#comment-24539)) + +> Bryan Buchanan says: +> +> Having played around with quite a few projects (after using the Maven conversion tool) I have to say the VSCode integration is excellent. Well done. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-vscode-support-for-maven-projects.html) + + +### **N P** — August 22, 2023 at 8:23 pm ([permalink](https://www.codenameone.com/blog/better-vscode-support-for-maven-projects.html#comment-24568)) + +> N P says: +> +> VScode is telling me “found no favorite commands” when I click on favorites +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-vscode-support-for-maven-projects.html) + + +### **Shai Almog** — August 23, 2023 at 2:00 am ([permalink](https://www.codenameone.com/blog/better-vscode-support-for-maven-projects.html#comment-24569)) + +> Shai Almog says: +> +> Did you download the VSCode version of the project from start or did you get a project from a different source? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-vscode-support-for-maven-projects.html) + + +### **Raphael Lacuna** — September 23, 2023 at 12:02 am ([permalink](https://www.codenameone.com/blog/better-vscode-support-for-maven-projects.html#comment-24575)) + +> Raphael Lacuna says: +> +> I have the same issue, and I downloaded it from the VSCode version of the project +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-vscode-support-for-maven-projects.html) + + +### **Steve Hannah** — September 23, 2023 at 12:50 pm ([permalink](https://www.codenameone.com/blog/better-vscode-support-for-maven-projects.html#comment-24576)) + +> Steve Hannah says: +> +> Just tested on a fresh project and seemed to work. +> In the Explorer, expand “Maven” +> You’ll see: +> your-app +> your-app-anroid +> your-app-common +> your-app-ios +> your-app-javascript +> … +> +> Expand the “your-app” one. +> Then expand “Favourites” +> +> You should see all of the key build and run commands there. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbetter-vscode-support-for-maven-projects.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/big-batch-of-features.md b/docs/website/content/blog/big-batch-of-features.md new file mode 100644 index 0000000000..40a7b54b2b --- /dev/null +++ b/docs/website/content/blog/big-batch-of-features.md @@ -0,0 +1,115 @@ +--- +title: Big Batch Of Features +slug: big-batch-of-features +url: /blog/big-batch-of-features/ +original_url: https://www.codenameone.com/blog/big-batch-of-features.html +aliases: +- /blog/big-batch-of-features.html +date: '2013-06-29' +author: Shai Almog +--- + +![Header Image](/blog/big-batch-of-features/big-batch-of-features-1.png) + + + + +[ +![Multi Column Generic Spinner](/blog/big-batch-of-features/big-batch-of-features-1.png) +](/img/blog/old_posts/big-batch-of-features-large-5.png) + + + +We’ve been so busy this past month that we just forgot mentioning many of the features that went into Codename One in June and + + + +there are MANY small features that just didn’t get a blog post or even a mention! + + +We just open sourced a major piece of our backend code, the changes to retroweaver and library code that allow us to compile Java SE 5 code to J2ME/RIM. With this change in place we will start using Java 5 features throughout the code but mostly transition towards using ArrayList/HashMap and the base collection interfaces rather than Vector/Hashtable. + + + + + + + +On the right you should see the multi column generic spinner used in the +[ +Maker +](/maker.html) +GUI builder, its right columns are filled dynamically based on the layout type. This is pretty easy to accomplish even from the GUI builder. The Generic spinner’s methods now accept an offset for the column and change the values/model within the given column. + +Paul Harrison Williams contributed an +[ +XML +](http://code.google.com/p/codenameone/issues/detail?id=753) +[ +writer +](http://code.google.com/p/codenameone/issues/detail?id=753) +implementation that allows you to serialize XML Elements to a stream. + + +Probably the most interesting/important feature + +is two new scale modes in Style: Scale to fit and Scale to fill. When you set a bg image to a style (either via the designer or in code) you can set the image behavior. The default is scaled, which never really made much sense. You can also tile or align the image in many ways but up until now we were missing two very basic and important features: + + * +Scale to fit scales the image so it will fit on the component while maintaining its aspect ratio. It will leave the background in the bgColor if transparency is defined as expected. + + * +Scale to fill scales the image so it will fill the entire component while maintaining aspect ratio, in this case the image will usually “flow” out of the screen in one of its edges. + + +This is easier to explain with an example (in order scaled, scale to fit, scale to fill): + + + +* * * + +[ +![](/blog/big-batch-of-features/big-batch-of-features-2.png) +](/img/blog/old_posts/big-batch-of-features-large-6.png "Scaled - ignores aspect ratio and distorts the image") + +[ +![](/blog/big-batch-of-features/big-batch-of-features-3.png) +](/img/blog/old_posts/big-batch-of-features-large-7.png "Scale to fit - fills the background with bgColor and fits the image in the component") + +[ +![](/blog/big-batch-of-features/big-batch-of-features-4.png) +](/img/blog/old_posts/big-batch-of-features-large-8.png "Scale to fill - scales the image to fill the component while allowing for overflow") + + + +As part of this work we also added a flag to image download service allowing it to maintain the aspect ratio of downloaded images which is really useful when working with images off the internet from users photo albums etc. + + +Other than that we + +added a simple ability to create/delete contacts, this is rather basic but can help for many common use cases you can delete a contact using its “id” as: Display.getInstance().deleteContact(id); + + +You can also create a basic contact using: + + +Display.getInstance().createContact(firstName, familyName, officePhone, homePhone, cellPhone, email); + + +We made some enhancements to our Facebook support as well but one + +of the more interesting ones is the ability to sign in to an App without a user visible OAuth process. This will grant you the ability to access public information on Facebook (e.g. pages, public posts/profiles etc.) but since no user will be logged in this won’t provide an “identity”. Note that you will still need to create a Facebook App to associate with the requests, then you can just login using: + + + +FacebookAccess.anonymousLogin(appid, clientSecret); + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/big-changes-bootcamp-updates.md b/docs/website/content/blog/big-changes-bootcamp-updates.md new file mode 100644 index 0000000000..6fc8c986b6 --- /dev/null +++ b/docs/website/content/blog/big-changes-bootcamp-updates.md @@ -0,0 +1,78 @@ +--- +title: Big Changes and Bootcamp Updates +slug: big-changes-bootcamp-updates +url: /blog/big-changes-bootcamp-updates/ +original_url: https://www.codenameone.com/blog/big-changes-bootcamp-updates.html +aliases: +- /blog/big-changes-bootcamp-updates.html +date: '2017-04-10' +author: Shai Almog +--- + +![Header Image](/blog/big-changes-bootcamp-updates/full-stack-java-bootcamp.jpg) + +Since I haven’t blogged in a while a lot of stuff has piled up on my desk and I’ll get it out in batches in this post I’ll go over a few of the bigger changes we did while I was away on the bootcamp and also give you a bit of an update on what we’ve been doing within the bootcamp itself. + +The week before we launched the bootcamp our Mac build servers reached a very heavy workload, this was becoming disruptive to our general developer population as builds got queued at a high rate. After a bit of investigation it seems that this could usually be pinned to specific users with **very** long build times. + +Normally build time is divided as: + + * Upload + + * Queued + + * Build + + * Upload result + +The latter is pretty fast since our servers have a very fast connection, the first depends on your Internet speed however the queue is problematic…​ + +We have a limited number of servers, if the build time is too long our servers can become occupied and then people will remain in queue for quite a long time. Worse, because our queue system is biased based on grade if a paying or a few high ranking paying user send builds in succession this might create a situation where low ranking users (free or basic) might be denied access to the server as a higher rank user will constantly step ahead in line. + +Slow builds hurt everyone, up until now we always assumed people would align and try to avoid slow builds but I’m guessing that was naive. The incentive to do that isn’t enough. So we installed a timeout quota on a portion of the build phase which limited some builds. + +It was a bad idea to do this right before the bootcamp but I felt some urgency due to the large amount of queuing. Initially we limited the time to 15 minutes on the xcode compile phase which is normally around 1.5-2 minutes. Due to some complaints I raised it to 25 minutes and some people still couldn’t get their builds thru (this should give you a sense of how problematic this traffic jam was). Finally Dave produced an idea for improvement in the build process that we implemented and deployed this weekend and it should produce faster builds for those use cases. I don’t see a difference with my builds but if your builds were taking 50 minutes they should be much faster now. + +This change shouldn’t impact most users but since it changes the way headers are included some native code that relies on headers being included by VM generated code might fail. + +### Read Response for Errors + +Another potentially disruptive change we released this weekend is a flipped default on `readResponseForErrors`. Normally when you get an error from the server (e.g. 404) the `readResponse` method of connection request isn’t invoked and you can’t read the error message. + +This seems to make sense but it causes two big problems: + + * When working with webservices you often get an error code and text describing the error which you would want to read + + * The network monitor won’t show the error response either…​ + +So we flipped the default to read the response for error codes. This shouldn’t impact most applications but if yours is impacted you can restore the old behavior either by using `setReadResponseForErrors(false)` on the connection request or do `ConnectionRequest.setReadResponseForErrorsDefault(false);` to disable this globally. + +### Bootcamp Update + +We just finished the first 2 weeks (10 missions) of the bootcamp and will resume the last 2 weeks on the 18th of April (at which point we will again suspend the blog posts). + +We are covering a lot of material, in some regards more than I expected. I know I’ve personally learned a lot from interacting more closely with the developers in the bootcamp and I think I have a better sense of the pain points. I’ve already made a lot of commits to the project over the last few days to address some of the pain points I felt during the bootcamp but some are harder to fix with a few commits. + +Once the bootcamp is over I plan to redo a lot of the videos in the site and rework some of our tools/tutorials. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **salah Alhaddabi** — April 18, 2017 at 3:40 pm ([permalink](https://www.codenameone.com/blog/big-changes-bootcamp-updates.html#comment-23448)) + +> salah Alhaddabi says: +> +> Very nice Shai and hope the result of the bootcamp will be fruitful and lead to better tutorials/documentation +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-bootcamp-updates.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/big-changes-jcef.md b/docs/website/content/blog/big-changes-jcef.md new file mode 100644 index 0000000000..d7678f905f --- /dev/null +++ b/docs/website/content/blog/big-changes-jcef.md @@ -0,0 +1,396 @@ +--- +title: Big Changes and CEF +slug: big-changes-jcef +url: /blog/big-changes-jcef/ +original_url: https://www.codenameone.com/blog/big-changes-jcef.html +aliases: +- /blog/big-changes-jcef.html +date: '2020-07-16' +author: Shai Almog +--- + +![Header Image](/blog/big-changes-jcef/generic-java-2.jpg) + +Today we released one of the biggest changes to Codename Ones simulator in ages. We added the ability to use CEF (Chrome Embedding Framework). This is **currently** off by default but even if you don’t use it you might feel the impact so it’s crucial that you read this post. + +__ | Updated July 31st with additional platform instructions below +---|--- + +__ | Updated August 2nd with correction to the Linux install script +---|--- + +__ | Updated August 4th with another correction to the Linux install script +---|--- + +### The TL;DR + +The big change for those of you who don’t care about the details is this: FX will no longer install automatically if it’s missing. That might be a good thing for some applications. But if you rely on media/web things might break in the simulator/debugger. + +The short term workaround is to install a JVM that supports JavaFX out of the box such as [ZuluFX](https://www.azul.com/downloads/zulu-community/) and make sure your IDE uses it. Make sure it’s first in your path and that JAVA_HOME points at it. + +Another option is to migrate to CEF which might not be an option right now if your needs are mostly media related. Read on for the details. + +### Why? + +I wrote before about our [desire to kick JavaFX and its problems to the curve](https://www.codenameone.com/blog/moving-away-from-fx.html). There’s no way around it. It’s outdated and buggy. + +CEF is literally Chrome. It’s modern and up to date, so newer browser features behave as expected. It’s also easy to debug and has a lot of other great features we can use. It would also free us from some of the JVM dependencies and let us build smaller desktop apps moving forward. + +The reason we really need it at this moment is support for WebRTC which isn’t available in the JavaFX version of the browser but is available in Chromium. + +__ | You can easily debug CEF `BrowserComponent` in Chrome by navigating to in Chrome +---|--- + +### How will this Impact Me? + +Hopefully you won’t run into any problem. If you’re using a JDK that doesn’t include JavaFX you might run into a problem in this transition period and things might fail. We recommend [ZuluFX](https://www.azul.com/downloads/zulu-community/) for now. + +__ | Once this transition period is done this should work with any JVM +---|--- + +By default CEF is off but you can turn it on explicitly instead of installing JavaFX. + +### Turn on CEF + +**This post was updated on July 31st with details on all platforms** + +When complete we will automatically download and install CEF on the first activation effectively disabling the JavaFX mode. + +If the `~/.codenameone/cef` directory is present we assume CEF is installed and try to load it instead of JavaFX. + +#### Mac Install + +To install manually download [this file](https://github.com/shannah/codenameone-cef/blob/master/dist/cef-mac.zip?raw=true). Then perform the following command in the terminal: + + + unzip ~/Downloads/cef-mac.zip -d ~/.codenameone + +To uninstall CEF in case of a problem do: + + + rm -Rf ~/.codenameone/cef + +#### Windows Install + +If you’re using Win32 download [this file](https://github.com/shannah/codenameone-cef/blob/master/dist/cef-win32.zip?raw=true). + +For Win64 download [this file](https://github.com/shannah/codenameone-cef/blob/master/dist/cef-win64.zip?raw=true). + +Open your user directory and search for the `.codenameone` directory. In that directory unzip the downloaded zip file. It should include a `cef` directory. If not make sure to unzip the content into a directory named `cef`. + +You can uninstall it by deleting the `cef` directory at any time. + +#### Linux Install + +__ | We only support 64 bit Linux at this time. If there are developers using 32 bit Linux as their desktops please let us know +---|--- + +Download the file [this file](https://github.com/shannah/codenameone-cef/blob/master/dist/cef-linux64.zip?raw=true). + +Then install using: + + + mkdir ~/.codenameone/cef + unzip cef-linux64.zip -d ~/.codenameone/cef + chmod 755 ~/.codenameone/cef/lib/linux64/jcef_helper + +To uninstall CEF in case of a problem do: + + + rm -Rf ~/.codenameone/cef + +#### What’s Missing? + +With the CEF pipeline media is implemented using the browser component. So videos literally play in the Chrome browser (seamlessly, you wouldn’t know). This removes the need for JavaFX completely and simplifies a lot of things. + +However, there’s one missing piece at the moment: h264 support. + +By default JCEF doesn’t include the h264 codec due to patent restrictions. This isn’t a problem for our use case but it means we need to get a binary build of CEF working and the build environment for Chrome is “tough”. So right now h264 isn’t working. + +Other than that we’re still missing Windows and Linux support. We’re also missing an installer that will deliver CEF seamlessly. All of those will ship together as part of an update in the next couple of weeks once all issues are resolved. + +### How does this Work? + +Up until now the JavaSE port had one version which was `JavaSEPort`. This is now a base class for three implementations: + + * **JavaFX** — a compatibility mode implementation which is currently the default. + + * **CEF** — the new mode which will run if the cef directory is available/ + + * **JMF** — a special case that uses Java Media Framework for media playback instead of JavaFX or JCEF. It has the advantage of being very small. It works very similarly to the CEF approach by searching for the JMF jar in the `.codenameone` directory and using it if it’s available. We’re not sure this is a use case worth pursuing. + +On launch we pick the best option. If CEF is available under the `.codenameone` directory we pick that implementation. This uses the native library and integrates directly into the UI. + +### Up Next + +Once this migration is done we’ll follow up with some posts on debugging under CEF etc. Please let us know if you run into trouble ASAP. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Durank** — July 17, 2020 at 12:12 pm ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24298)) + +> [Durank](https://avatars0.githubusercontent.com/u/16245755?v=4) says: +> +> when this post it will be available to windows? this means that the actual simulator will not work? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Shai Almog** — January 20, 2021 at 2:26 am ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24384)) + +> Shai Almog says: +> +> See the section titled: “Windows Install” above… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Steve Hannah** — July 17, 2020 at 1:48 pm ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24299)) + +> [Steve Hannah](https://lh3.googleusercontent.com/a-/AAuE7mBmUCgKSZtJ2cqeHgj6bdPY2AAQ10roHlMpgRWc) says: +> +> Windows will be available soon. +> The simulator will still work without CEF. If you are on Windows, and your app doesn’t use Media or BrowserComponent, then it will still work fine (without CEF). If your app uses Media or BrowserComponent, then just make sure you’re using a JDK that has JavaFX, such as ZuluFX – and it will work fine. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Angelo** — August 3, 2020 at 1:53 pm ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24303)) + +> Angelo says: +> +> I think that the CEF install instructions for Linux are wrong, because the zip file has not cef as root so the unzipping happens, but I had to create manually the cef folder and copy the zip content there. I hope it is useful. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Angelo** — August 3, 2020 at 2:01 pm ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24304)) + +> Angelo says: +> +> As for the cef loading into the IDE, no updates are available for IntellJ Idea so, being that it seems that I cannot receive the codename updates as soon as they are published, I have to wait for the IDE update. Unless there is a workaround that you know to force the update. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Shai Almog** — August 4, 2020 at 3:34 am ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24305)) + +> Shai Almog says: +> +> Ugh. I’ll fix the instructions for that. Thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Shai Almog** — August 4, 2020 at 3:36 am ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24302)) + +> Shai Almog says: +> +> We push updates separately from the plugins. That way we can support 3 IDEs with more common code. Just update via Codename One Settings using the menu on the top right. +> If you still have the old settings UI it’s under the Basic section. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Angelo** — August 4, 2020 at 7:42 am ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24309)) + +> Angelo says: +> +> The settings app found that there was a lock file in the .codename directory. I had to delete it to perform the update. +> It is possible that also the other Codename plugin updates on my environment were blocked by that. Maybe the automatic update procedure should check it and inform the user, in case. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Richard Matovu** — August 9, 2020 at 9:13 am ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24317)) + +> [Richard Matovu](https://lh3.googleusercontent.com/a-/AOh14Ggv6DF23oF-udh-1mkmXOx1WryNt3gP1I1fADw2) says: +> +> I have intergrated CEF in my project and it runs well. When i came to the point where it had to show a browser component, it showed an error “An internal application error occured: java.lang.RuntimeException: Failed to create CEF browser” and in the console it displayed: +> CEF Args: [–disable-gpu, –disable-software-rasterizer, –disable-gpu-compositing, –touch-events=enabled, –enable-media-stream, –device-scale-factor=4, –force-device-scale-factor=4, –autoplay-policy=no-user-gesture-required, –enable-usermedia-screen-capturing] +> java.lang.RuntimeException: Failed to create CEF browser +> at com.codename1.impl.javase.cef.JavaCEFSEPort.createCEFBrowserComponent(JavaCEFSEPort.java:106) +> at com.codename1.impl.javase.cef.JavaCEFSEPort.createBrowserComponent(JavaCEFSEPort.java:81) +> at com.codename1.ui.BrowserComponent$9.run(BrowserComponent.java:531) +> [EDT] 0:0:19,935 – Exception: java.lang.RuntimeException – Failed to create CEF browser +> at com.codename1.ui.Display.processSerialCalls(Display.java:1331) +> at com.codename1.ui.Display.edtLoopImpl(Display.java:1274) +> at com.codename1.ui.Display.mainEDTLoop(Display.java:1162) +> at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120) +> at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176) +> Caused by: java.lang.reflect.InvocationTargetException +> at java.desktop/java.awt.EventQueue.invokeAndWait(EventQueue.java:1367) +> at java.desktop/java.awt.EventQueue.invokeAndWait(EventQueue.java:1342) +> at com.codename1.impl.javase.cef.JavaCEFSEPort.createCEFBrowserComponent(JavaCEFSEPort.java:99) +> … 7 more +> Caused by: java.lang.UnsatisfiedLinkError: /home/donrix/.codenameone/cef/lib/linux64/libjcef.so: libjawt.so: cannot open shared object file: No such file or directory +> at java.base/java.lang.ClassLoader$NativeLibrary.load0(Native Method) +> at java.base/java.lang.ClassLoader$NativeLibrary.load(ClassLoader.java:2442) +> at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2498) +> at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2694) +> at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2640) +> at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:830) +> at java.base/java.lang.System.loadLibrary(System.java:1873) +> at org.cef.SystemBootstrap$1.loadLibrary(SystemBootstrap.java:24) +> at org.cef.SystemBootstrap.loadLibrary(SystemBootstrap.java:36) +> at org.cef.CefApp.startup(CefApp.java:536) +> at com.codename1.impl.javase.cef.CEFBrowserComponent.create(CEFBrowserComponent.java:178) +> at com.codename1.impl.javase.cef.CEFBrowserComponent.create(CEFBrowserComponent.java:170) +> at com.codename1.impl.javase.cef.CEFBrowserComponent.create(CEFBrowserComponent.java:167) +> at com.codename1.impl.javase.cef.JavaCEFSEPort.createCEFBrowserComponent(JavaCEFSEPort.java:112) +> at com.codename1.impl.javase.cef.JavaCEFSEPort$2.run(JavaCEFSEPort.java:102) +> at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:303) +> at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770) +> at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) +> at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) +> at java.base/java.security.AccessController.doPrivileged(Native Method) +> at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) +> at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740) +> at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) +> at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) +> at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) +> at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) +> at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) +> at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Shai Almog** — August 10, 2020 at 5:09 am ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24311)) + +> Shai Almog says: +> +> Thanks. Can you please post an issue about this in the issue tracker. Please also include some information about your system such as env output, distro etc. The issue tracker is here: +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Carlos Verdier** — August 14, 2020 at 9:28 am ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24323)) + +> [Carlos Verdier](https://lh3.googleusercontent.com/-y-v_mMAwszk/AAAAAAAAAAI/AAAAAAAAAAA/AMZuucmcoea9nf4P3gRHGzB7T7jxG98R1w/photo.jpg) says: +> +> Not working for me. Whenever I try to play a video or open a browser, it refuses with this output: +> +> “/Users/carlos/.codenameone/cef/macos64/libjcef.dylib: dlopen(/Users/carlos/.codenameone/cef/macos64/libjcef.dylib, 1): no suitable image found. Did find: +> /Users/carlos/.codenameone/cef/macos64/libjcef.dylib: code signature in (/Users/carlos/.codenameone/cef/macos64/libjcef.dylib) not valid for use in process using Library Validation: library load disallowed by system policy” +> +> Tested on Mac OS Catalina 10.15.6 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Steve Hannah** — August 14, 2020 at 12:52 pm ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24324)) + +> [Steve Hannah](https://lh3.googleusercontent.com/a-/AAuE7mBmUCgKSZtJ2cqeHgj6bdPY2AAQ10roHlMpgRWc) says: +> +> I haven’t been able to reproduce this error, but I’ve found lots of bug reports around the internet related to Catalina. It could be related to the JDK that you’re using, if it is signed/notarized. Or it could be related to restrictive settings in Catalina. +> +> Can you file this in the issue tracker so we can track it. As a starting point, what JDK are you using? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Artur Hefczyc** — August 27, 2020 at 9:20 pm ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24331)) + +> [Artur Hefczyc](https://avatars3.githubusercontent.com/u/1848738?v=4) says: +> +> On Macs downloaded files are often automatically unzipped. In such a case, you can add that info to install the cef using move command instead: +> “` +> mv ~/Downloads/cef ~/.codenameone/ +> “` +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Artur Hefczyc** — August 28, 2020 at 7:21 pm ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24326)) + +> [Artur Hefczyc](https://avatars3.githubusercontent.com/u/1848738?v=4) says: +> +> I have installed cef as instructed above. However, when I run my app in simulator I still see +> “` +> CSS> JavaFX is loaded +> “` +> in the console output. Is this expected? I mean, do you still use JavaFX in simulator even if cef is installed? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Shai Almog** — August 29, 2020 at 4:34 am ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24330)) + +> Shai Almog says: +> +> I think that’s a buggy printout from the prior condition. It indicates you have JavaFX in your system but it probably still uses CEF anyway. I filed an issue on that here: +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Artur Hefczyc** — September 11, 2020 at 3:44 am ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24334)) + +> [Artur Hefczyc](https://avatars3.githubusercontent.com/u/1848738?v=4) says: +> +> So, how to make sure I am running in CEF mode instead of JavaFX? Is there any way to confirm the env my app us running in? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Shai Almog** — September 11, 2020 at 3:45 am ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24332)) + +> Shai Almog says: +> +> If in chrome shows the debugging options for the browser then CEF is working as expected +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Artur Hefczyc** — September 11, 2020 at 4:49 pm ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24336)) + +> [Artur Hefczyc](https://avatars3.githubusercontent.com/u/1848738?v=4) says: +> +> Neither with my app running in simulator or running as a compiled desktop app Chrome shows anything at this address: +> “` +> This site can’t be reached +> localhost refused to connect. +> “` +> +> The cef folder exist: +> “` +> $ ll ~/.codenameone/cef +> total 720 +> -rw-r–r–@ 1 usr staff 170K Jul 10 15:12 jcef-tests.jar +> -rw-r–r–@ 1 usr staff 185K Jul 10 15:12 jcef.jar +> drwxr-xr-x@ 8 usr staff 256B Jul 10 15:12 macos64 +> “` +> +> Do you have any suggestions on what can be wrong? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Shai Almog** — September 11, 2020 at 4:51 pm ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24333)) + +> Shai Almog says: +> +> Is this not reachable when a browser component is physically on the screen? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + + +### **Julio Valeriron Ochoa** — January 19, 2021 at 8:49 pm ([permalink](https://www.codenameone.com/blog/big-changes-jcef.html#comment-24383)) + +> Julio Valeriron Ochoa says: +> +> how can I configure new cfe simulator in windows? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbig-changes-jcef.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/block-copy-paste-faster-performance-ios.md b/docs/website/content/blog/block-copy-paste-faster-performance-ios.md new file mode 100644 index 0000000000..adf6cb2278 --- /dev/null +++ b/docs/website/content/blog/block-copy-paste-faster-performance-ios.md @@ -0,0 +1,58 @@ +--- +title: Block Copy/Paste & Faster Performance on iOS +slug: block-copy-paste-faster-performance-ios +url: /blog/block-copy-paste-faster-performance-ios/ +original_url: https://www.codenameone.com/blog/block-copy-paste-faster-performance-ios.html +aliases: +- /blog/block-copy-paste-faster-performance-ios.html +date: '2017-02-06' +author: Shai Almog +--- + +![Header Image](/blog/block-copy-paste-faster-performance-ios/security.jpg) + +I discussed both of these last week but we’ve made some progress that warrants a dedicated post. We added a new feature that allows you to [block copy & paste](/blog/disable-screenshots-copy-paste.html) on a text component either globally or on a case by case basis. This is helpful for highly sensitive applications. + +This feature was previously restricted to Android but is now available to iOS as well with no change required to your code. + +### Build Performance + +What started as a bunch of optimizations to fix [issue 2024](https://github.com/codenameone/CodenameOne/issues/2024) evolved to a set of optimizations that should make the generated iOS code more readable, smaller & faster. This took some twists and turns and for now we reverted this set of changes until next Friday. + +However, the end result is that this should also shorten build times noticeably although not for everyone…​ + +The `clang` compiler is very slow when dealing with large methods and macros. By optimizing away some of the more ASM oriented conventions of the bytecode and substituting them with direct variable/constant usage we reduced some overheads. + +If you weren’t directly impacted by this you probably won’t see any performance impact. The speed of the JVM rarely factors into the performance of Codename One which is governed more by the speed of the native port than anything else. +One of the things to notice in the issue discussion is that the original optimization fixed the problem while causing worse compilation times for different code pathways. That’s why optimizations & fixes are so tricky in a product as big as Codename One as regressions can be very complicated. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **M Usman Nu** — February 10, 2017 at 1:52 pm ([permalink](https://www.codenameone.com/blog/block-copy-paste-faster-performance-ios.html#comment-23327)) + +> M Usman Nu says: +> +> Do i need to add ios.disableScreenshots in built-hints in order to enable this feature ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fblock-copy-paste-faster-performance-ios.html) + + +### **Shai Almog** — February 11, 2017 at 5:57 am ([permalink](https://www.codenameone.com/blog/block-copy-paste-faster-performance-ios.html#comment-23098)) + +> Shai Almog says: +> +> No, that has nothing to do with that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fblock-copy-paste-faster-performance-ios.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/blog-vacation.md b/docs/website/content/blog/blog-vacation.md new file mode 100644 index 0000000000..31a78fa18b --- /dev/null +++ b/docs/website/content/blog/blog-vacation.md @@ -0,0 +1,27 @@ +--- +title: Blog Vacation +slug: blog-vacation +url: /blog/blog-vacation/ +original_url: https://www.codenameone.com/blog/blog-vacation.html +aliases: +- /blog/blog-vacation.html +date: '2016-12-20' +author: Shai Almog +--- + +![Header Image](/blog/blog-vacation/happy-holidays.jpg) + +Happy holidays, Merry Christmas, happy new year to all. All of us here at Codename One hope you have +a lovely vacation if you are taking one. Since half of our readership is from countries that celebrate these +holidays it seems like a good time to take a short blogging vacation as well. + +We’re still working here and will make releases/offer support as usual but we’ll update you on the changes we +had in our 2017 posts. We’ll be back to blogging on January 2nd. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/bluetooth-support.md b/docs/website/content/blog/bluetooth-support.md new file mode 100644 index 0000000000..4080a5d2ba --- /dev/null +++ b/docs/website/content/blog/bluetooth-support.md @@ -0,0 +1,53 @@ +--- +title: Bluetooth Support +slug: bluetooth-support +url: /blog/bluetooth-support/ +original_url: https://www.codenameone.com/blog/bluetooth-support.html +aliases: +- /blog/bluetooth-support.html +date: '2016-05-29' +author: Shai Almog +--- + +![Header Image](/blog/bluetooth-support/bluetooth.jpg) + +Bluetooth is one of those specs that makes me take a step back…​ It’s nuanced, complex and multi-layered. +That isn’t necessarily bad, it solves a remarkably hard problem. Unfortunately when people say the words “bluetooth +support” it’s rare to find two people who actually mean the same thing! + +So while we did have a lot of requests for bluetooth support over the years most of them were too vague and when +we tried to follow thru we usually reached a dead end where the customers themselves often didn’t really know +the part of the spec they wanted. + +Normally when something is so huge and vague we try to look at what the native OS’s did, but iOS and Android took +very different routes to bluetooth. + +Another approach is to look at what other companies in the field did to support bluetooth and historically there +wasn’t much. Most “Write Once Run Anywhere” solutions just ignored that feature. + +However, recently we became aware of [this bluetooth plugin for Cordova](https://github.com/randdusing/cordova-plugin-bluetoothle) +which Chen and Steve adapted to a Codename One cn1lib [here](https://github.com/chen-fishbein/bluetoothle-codenameone). + +Check it out and let us know what you think…​ +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Nick Koirala** — June 2, 2016 at 2:55 am ([permalink](https://www.codenameone.com/blog/bluetooth-support.html#comment-22554)) + +> Nick Koirala says: +> +> Nice, just built the demo and found it picking things up. Can it scan in the background and call back to the app? I.e., for discovering beacons. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbluetooth-support.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/book-continued-migration.md b/docs/website/content/blog/book-continued-migration.md new file mode 100644 index 0000000000..ef417dd447 --- /dev/null +++ b/docs/website/content/blog/book-continued-migration.md @@ -0,0 +1,50 @@ +--- +title: Book & Continued Migration +slug: book-continued-migration +url: /blog/book-continued-migration/ +original_url: https://www.codenameone.com/blog/book-continued-migration.html +aliases: +- /blog/book-continued-migration.html +date: '2015-06-28' +author: Shai Almog +--- + +![Header Image](/blog/book-continued-migration/codenameone-fr-book.png) + +[Eric Dodji Gbofu](http://www.codenameonefr.com) has been working on a Codename One book in French for +the past year and [it finally came out](http://www.d-booker.fr/cn1/214-codename-one.html)! +I’m still waiting on my copy mostly to show to French speakers we meet (I have a very hard time picking languages), I’m +pretty sure its a cool book. Chen and I wrote the forward for the book, I trust Eric did a great job in it just like he has done with +[Codename One Fr](http://www.codenameonefr.com). +You can order the book either directly thru the [publishers site](http://www.d-booker.fr/cn1/214-codename-one.html) +(which is apprently the preferred way) or thru [Amazon](http://www.amazon.fr/Codename-One-D%C3%A9velopper-Android-Blackberry/dp/2822703485). + +We hope many of you purchase this book, if there is interest in it then it might prompt further updates and additional publishers. + +#### App Engine Migration Part III + +This is going to be a long and winding saga covering the migration process of our backend servers from App Engine +to a more “hands on” architecture. The build servers storage aspect already migrated to S3 and seem to be functioning +reasonably well. We are now setting our focus on several different features, the first of which is +[crash reporting](/how-do-i---use-crash-protection-get-device-logs.html). + +An important feature within crash reporting is the feature that allows sending an email with your log file from the device, +with new builds this will use our new webservice that no longer uses app engine. It will also switch to using sendgrid +for the actual email delivery… +This should improve the functionality considerably since unlike app engine the log will now be embedded into the body +of the email thus allowing you to use email filters etc. It will also solve the issue of log files no longer being available. + +We will now also quota emails so no more than 1 email per minute can be sent (per user) and no more than 200 +per 48 hours. This will prevent some cases we had in the past from recurring where a wayward app update +decimated users inboxes. + +This is yet another step in an ongoing process, we intend to shift device registration/push to the new servers as soon +as possible which should open up a whole set of possibilities. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/bootcamp-parse-bouns-post-materials.md b/docs/website/content/blog/bootcamp-parse-bouns-post-materials.md new file mode 100644 index 0000000000..38164a4ca6 --- /dev/null +++ b/docs/website/content/blog/bootcamp-parse-bouns-post-materials.md @@ -0,0 +1,91 @@ +--- +title: Bootcamp Parse Bonus and post Materials +slug: bootcamp-parse-bouns-post-materials +url: /blog/bootcamp-parse-bouns-post-materials/ +original_url: https://www.codenameone.com/blog/bootcamp-parse-bouns-post-materials.html +aliases: +- /blog/bootcamp-parse-bouns-post-materials.html +date: '2017-03-14' +author: Shai Almog +--- + +![Header Image](/blog/bootcamp-parse-bouns-post-materials/full-stack-java-bootcamp.jpg) + +I might have been unclear with about the bootcamp materials. It’s possible I implied that the materials will be available later. They won’t…​ +It would be unfair to our bootcamp participants if the thing they pay for is then made available for free. There will be some content that we will make available some content that will be available as paid material (a course) and some content that will be 100% exclusive. + +I don’t think we’ll offer anything remotely close to the deal we have with the bootcamp…​ + +### Parse + +One of the things discussed by people who contacted me is parse support. I wanted to talk about that in the bootcamp but decided it would be too much of a detour for me to cover that material. Then I got into a discussion with +[Chidiebere G.U. Okwudire](https://www.codenameone.com/blog/how-i-chose-my-replacement-for-parse-com.html) who wrote the parse4cn1 cn1lib and maintains it. + +As part of that we’ll add a workshop day to the bootcamp where he can cover Parse, parse4cn1 & maybe provide some insight into the process of extending Codename One from the outside. I’m sure it will be illuminating to all of us (myself included). + +### What is Codename One + +I’ve spent some time building materials for the pre-course which runs before the bootcamp starts and it covers some of the big pieces of Codename One to make sure we all start on the same page. One of the features I’ve made is the “long version” of the answer to “what is Codename One”. This answer goes into the details of history, architecture (big pieces), how does it work and lightweight architecture. + +This is a small piece of some of the things we are working on: + +And the slides I show within the video are here: + +**[What is codename one](//www.slideshare.net/vprise/what-is-codename-one "What is codename one") ** from **[Shai Almog](//www.slideshare.net/vprise)** + +### Are you Still Waiting? + +If you haven’t signed up for the bootcamp yet this is pretty much your last chance…​ Registration will close up soon and as I said before we won’t have a better offer in the future because it’s just impossible. + +Any future course will not be cheap, won’t include any of the big ticket items like one on one talks or group support. No course in the future will include the enterprise plan bundled in either. + +This is the last full day of registration so if you still didn’t signup I suggest rushing it because registration will close…​ +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — March 15, 2017 at 3:37 pm ([permalink](https://www.codenameone.com/blog/bootcamp-parse-bouns-post-materials.html#comment-23009)) + +> Chidiebere Okwudire says: +> +> I’m definitely looking forward to the bootcamp and the extra Parse workshop! Feel free to let me know what aspects of Parse and parse4cn1 you’d like to see so that I can prepare accordingly. Just reply to this post with your ideas/questions. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbootcamp-parse-bouns-post-materials.html) + + +### **Andrew Nyago** — March 15, 2017 at 3:38 pm ([permalink](https://www.codenameone.com/blog/bootcamp-parse-bouns-post-materials.html#comment-23166)) + +> Andrew Nyago says: +> +> i don;t see any link to a registration page for the bootcamp. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbootcamp-parse-bouns-post-materials.html) + + +### **Jared Ruplinger** — March 15, 2017 at 4:15 pm ([permalink](https://www.codenameone.com/blog/bootcamp-parse-bouns-post-materials.html#comment-23280)) + +> Jared Ruplinger says: +> +> [http://codenameone.teachabl…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbootcamp-parse-bouns-post-materials.html) + + +### **Chidiebere Okwudire** — March 15, 2017 at 5:35 pm ([permalink](https://www.codenameone.com/blog/bootcamp-parse-bouns-post-materials.html#comment-23314)) + +> Chidiebere Okwudire says: +> +> [http://codenameone.teachabl…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbootcamp-parse-bouns-post-materials.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/bottom-align.md b/docs/website/content/blog/bottom-align.md new file mode 100644 index 0000000000..33ccc3d953 --- /dev/null +++ b/docs/website/content/blog/bottom-align.md @@ -0,0 +1,146 @@ +--- +title: Bottom Align +slug: bottom-align +url: /blog/bottom-align/ +original_url: https://www.codenameone.com/blog/bottom-align.html +aliases: +- /blog/bottom-align.html +date: '2018-11-21' +author: Shai Almog +--- + +![Header Image](/blog/bottom-align/new-features-2.jpg) + +Box layout Y is one of the most used layouts in Codename One. It’s a wonderful, easy to use layout that makes vertical scrollable layout trivial. I love its simplicity, but sometimes that simplicity goes too far. A good example of that is the a common layout where we have a button at the bottom of the screen. + +Historically we solved this by nesting box into a border layout: + + + Form f = new Form("Border Layout", new BorderLayout()); __**(1)** + + Container box = new Container(BoxLayout.y()); + box.setScrollableY(true); __**(2)** + + Button b = new Button("Add New Button"); + + b.addActionListener(e -> { + MultiButton mb = new MultiButton("Added Button"); + box.addComponent(0, mb); + mb.setWidth(f.getWidth()); + mb.setY(f.getHeight()); + box.animateLayout(150); + }); + + f.add(SOUTH, b); + f.add(CENTER, box); + + f.show(); + +__**1** | Border layout implicitly disables the default scrolling of the `Form` +---|--- +__**2** | Because of that we need to scroll the box layout + +When launched the UI looks like this: + +![Newly launched UI](/blog/bottom-align/bottom-y-layout-1.png) + +Figure 1. Newly launched UI + +![After adding a couple of elements it looks like this](/blog/bottom-align/bottom-y-layout-2.png) + +Figure 2. After adding a couple of elements it looks like this + +![After adding a lot of elements it looks like this](/blog/bottom-align/bottom-y-layout-3.png) + +Figure 3. After adding a lot of elements it looks like this + +Now this might be what you want. The add button is always clearly visible and easily accessible. However, in some cases this doesn’t work. + +Lets say you want this exact behavior like we see in the first two images. But once we reach the edge of the form you want the button to act as if this was a regular box layout. Effectively the button would either align to the bottom of the form or the edge of the layout. + +To accomplish this we are adding a new `yLast` mode in the `BoxLayout` which can be created using `BoxLayout.yLast()` or `new BoxLayout(BoxLayout.Y_AXIS_BOTTOM_LAST)`. E.g the code below will produce the exact same result for the first two images: + + + Form f = new Form("Border Layout", BoxLayout.yLast()); __**(1)** + Button b = new Button("Add New Button"); + b.addActionListener(e -> { + MultiButton mb = new MultiButton("Added Button"); + f.addComponent(0, mb); + mb.setWidth(f.getWidth()); + mb.setY(f.getHeight()); + f.getContentPane().animateLayout(150); + }); + + f.add(b); + + f.show(); + +__**1** | Box layout doesn’t disable the default scrollability of form +---|--- + +When it’s completely filled the button is pushed down out of the view area: + +![The button scrolls down when there is no more space](/blog/bottom-align/bottom-y-layout-4.png) + +Figure 4. The button scrolls down when there is no more space + +I like this approach as it reduces clutter for the UI and leaves more space available. It doesn’t fit for all cases but it’s a valuable addition to the API. These changes will be available with the update we’ll release this Friday. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — November 29, 2018 at 7:08 am ([permalink](https://www.codenameone.com/blog/bottom-align.html#comment-24075)) + +> Why did you use f.addComponent(0, mb);? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbottom-align.html) + + +### **Shai Almog** — November 29, 2018 at 7:35 am ([permalink](https://www.codenameone.com/blog/bottom-align.html#comment-24045)) + +> This adds the component to the first index in the component list. When I call add(Component) or addComponent(Component) it adds the component at the last offset which in this case will replace the existing “last component”. Here I added it to the top so a new entry will always appear first. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbottom-align.html) + + +### **Francesco Galgani** — November 29, 2018 at 7:46 am ([permalink](https://www.codenameone.com/blog/bottom-align.html#comment-24088)) + +> So in your example all the MultiButtons are disposed in inverted order of insertion, right? And if we want that every new MultiButton is added as penultimate? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbottom-align.html) + + +### **Shai Almog** — November 29, 2018 at 8:24 am ([permalink](https://www.codenameone.com/blog/bottom-align.html#comment-23823)) + +> No buttons are disposed but the new button is added to the top of the list instead of the bottom. That way the last button is always the add button. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbottom-align.html) + + +### **Francesco Galgani** — November 29, 2018 at 11:21 am ([permalink](https://www.codenameone.com/blog/bottom-align.html#comment-23894)) + +> Francesco Galgani says: +> +> Thank you for the quick reply. I’m sorry, my mistake: “disposed” is a false friend in my language, I wrote a thing thinking another. I understood your first reply. My question, in your example, is how to place the new added multibuttons to the bottom of list instead to the top. I mean if it’s possible something like: addComponent(n-2), where n is the number of added components to the container (plus the one we are going to add), n-1 is the Button always in the bottom, n-2 is the place to add a new multibutton. I guess that it’s not possible in this way. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbottom-align.html) + + +### **Shai Almog** — November 29, 2018 at 11:45 am ([permalink](https://www.codenameone.com/blog/bottom-align.html#comment-24080)) + +> Shai Almog says: +> +> It’s possible to call it that way. I just wanted to keep the code a bit simpler without a “weird” – offset calculation. I think it would be “cmpCount -1” but it might be “cmpCount -2” I don’t recall. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbottom-align.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/bouncy-castle-crypto-api.md b/docs/website/content/blog/bouncy-castle-crypto-api.md new file mode 100644 index 0000000000..ea03046863 --- /dev/null +++ b/docs/website/content/blog/bouncy-castle-crypto-api.md @@ -0,0 +1,143 @@ +--- +title: Bouncy Castle Crypto API +slug: bouncy-castle-crypto-api +url: /blog/bouncy-castle-crypto-api/ +original_url: https://www.codenameone.com/blog/bouncy-castle-crypto-api.html +aliases: +- /blog/bouncy-castle-crypto-api.html +date: '2013-06-05' +author: Shai Almog +--- + +![Header Image](/blog/bouncy-castle-crypto-api/bouncy-castle-crypto-api-1.png) + + + + + +![Picture](/blog/bouncy-castle-crypto-api/bouncy-castle-crypto-api-1.png) + + + + +We’ve got many requests in the past year for a cryptography API, initially we thought about adding something like this to the core but it seems somewhat niche so we decided to wrap up this great open source project and re-package it as a CodenameOne lib.The project is supported on all CodenameOne platforms right out of the box without any changes. + + + + +You can download the full source code as well as a compiled binary from a Google code project here: +[ +https://code.google.com/p/bouncy-castle-codenameone-lib/ +](https://code.google.com/p/bouncy-castle-codenameone-lib/) +and you can download the compiled binary from here: +[ +BouncyCastleCN1Lib.cn1lib +](https://code.google.com/p/bouncy-castle-codenameone-lib/source/browse/trunk/BouncyCastleCN1Lib.cn1lib) +(since Google removed the download section for new projects). + + +You can learn more about bouncy castle and how to use it through the + +many resources on available here: +[ +http://www.bouncycastle.org/ +](http://www.bouncycastle.org/) + +Happy coding! + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — June 27, 2013 at 5:43 pm ([permalink](https://www.codenameone.com/blog/bouncy-castle-crypto-api.html#comment-21701)) + +> Anonymous says: +> +> this is a very valuable addition ! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbouncy-castle-crypto-api.html) + + +### **Anonymous** — January 15, 2014 at 9:54 pm ([permalink](https://www.codenameone.com/blog/bouncy-castle-crypto-api.html#comment-22025)) + +> Anonymous says: +> +> can you please tell me, how i can get sha1 or md5 hashing of a string using this lib? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbouncy-castle-crypto-api.html) + + +### **Anonymous** — January 16, 2014 at 4:12 am ([permalink](https://www.codenameone.com/blog/bouncy-castle-crypto-api.html#comment-21919)) + +> Anonymous says: +> +> Did you try this: +> +> [https://www.google.com/sear…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbouncy-castle-crypto-api.html) + + +### **Anonymous** — October 26, 2014 at 6:27 am ([permalink](https://www.codenameone.com/blog/bouncy-castle-crypto-api.html#comment-21900)) + +> Anonymous says: +> +> I tried to search for AES string encription, but all examples forces me to use [java.security]().* (and I already have a working class for android written purely with [java.security/javax.crypto)]()), I need one for Your platform to cover the iPhone), which in return results with an error during compiling (error: package [java.security]() does not exist). BouncyCastle is installed. Any example written PURELY with BouncyCastle? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbouncy-castle-crypto-api.html) + + +### **Anonymous** — October 26, 2014 at 9:44 am ([permalink](https://www.codenameone.com/blog/bouncy-castle-crypto-api.html#comment-21995)) + +> Anonymous says: +> +> Did you try searching our discussion forum for aes? +> +> [https://groups.google.com/f…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbouncy-castle-crypto-api.html) + + +### **Anonymous** — October 26, 2014 at 3:52 pm ([permalink](https://www.codenameone.com/blog/bouncy-castle-crypto-api.html#comment-22105)) + +> Anonymous says: +> +> Actually, I did not. Thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbouncy-castle-crypto-api.html) + + +### **Kaya TC** — March 7, 2016 at 11:21 am ([permalink](https://www.codenameone.com/blog/bouncy-castle-crypto-api.html#comment-22700)) + +> Kaya TC says: +> +> Im having difficulties to Hash a passwordfield, i searched google for a while now, but the examples are not for cn1. +> I could not find some classes which are in the examples so im stuck now. +> +> I just want to have a SHA hash =) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbouncy-castle-crypto-api.html) + + +### **Shai Almog** — March 8, 2016 at 3:31 am ([permalink](https://www.codenameone.com/blog/bouncy-castle-crypto-api.html#comment-22458)) + +> Shai Almog says: +> +> I think this contains some examples which might be helpful: +> [http://www.programcreek.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbouncy-castle-crypto-api.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/braintree-paypal-cn1lib.md b/docs/website/content/blog/braintree-paypal-cn1lib.md new file mode 100644 index 0000000000..b18c54f644 --- /dev/null +++ b/docs/website/content/blog/braintree-paypal-cn1lib.md @@ -0,0 +1,125 @@ +--- +title: Braintree (PayPal) cn1lib +slug: braintree-paypal-cn1lib +url: /blog/braintree-paypal-cn1lib/ +original_url: https://www.codenameone.com/blog/braintree-paypal-cn1lib.html +aliases: +- /blog/braintree-paypal-cn1lib.html +date: '2017-05-01' +author: Shai Almog +--- + +![Header Image](/blog/braintree-paypal-cn1lib/new-features-3.jpg) + +As part of the bootcamp we wrote a couple of cn1libs and the first one is the [Braintree cn1lib](https://github.com/codenameone/BraintreeCodenameOne) which allows us to do credit card payments within an app. If you aren’t familiar with [Braintree](https://www.braintreepayments.com/) it’s a PayPal company that provides payment integration for mobile devices. + +Notice that this differs from [In App Purchase](https://www.codenameone.com/blog/intro-to-in-app-purchase.html) which targets “virtual goods”. This is useful for things like paying for physical goods and services e.g. paying for a taxi. + +In order to make a purchase with [this API](https://github.com/codenameone/BraintreeCodenameOne) we can use code such as: + + + Purchase.startOrder(new Purchase.Callback() { + public String fetchToken() { + // this method needs to return the token from the Brain tree server API. + // You need to use this code to connect to your server or return the data + // from a previous connection that fetched the token + } + + public void onPurchaseSuccess(String nonce) { + // this is a callback that will be invoked when the purchase succeeds + } + + public void onPurchaseFail(String errorMessage) { + // this is a callback that will be invoked when the purchase fails + } + + public void onPurchaseCancel() { + // this is a callback that will be invoked when the purchase is canceled + } + }); + +Notice that we don’t pass pricing or any other information within the code, this is all done in the server code that generates the token for the purchase. This allows our client code to remain “tamper proof”, all credit card collection and charge code is written by Braintree and is thus compliant with all the PCI level security restrictions and we can keep our code simple. + +Many basic and subtle hacks can be avoided, e.g. a common hack is to manipulate client side code to change charge pricing but since pricing is determined by our (your) server and communicated directly to the Braintree server this is 100% tamper proof. + +This is one of those cn1libs where most of the work is done in the server and so I’m only showing you the tip of the iceberg and you would need to followup with the [Braintree docs](https://developers.braintreepayments.com/start/overview) to understand how this is bound to your server then implement your server side logic. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Julien Sosin** — May 2, 2017 at 8:58 pm ([permalink](https://www.codenameone.com/blog/braintree-paypal-cn1lib.html#comment-23316)) + +> Julien Sosin says: +> +> Looks good ! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbraintree-paypal-cn1lib.html) + + +### **salah Alhaddabi** — May 3, 2017 at 1:39 pm ([permalink](https://www.codenameone.com/blog/braintree-paypal-cn1lib.html#comment-23498)) + +> salah Alhaddabi says: +> +> Extremely Excellent Work Shai. You guys always keep CN1 ahead of the game!!! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbraintree-paypal-cn1lib.html) + + +### **Edwin Quai Hoi** — May 4, 2017 at 6:53 am ([permalink](https://www.codenameone.com/blog/braintree-paypal-cn1lib.html#comment-21432)) + +> Edwin Quai Hoi says: +> +> hi is there a list of existing cn1libs anywhere +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbraintree-paypal-cn1lib.html) + + +### **Shai Almog** — May 5, 2017 at 4:44 am ([permalink](https://www.codenameone.com/blog/braintree-paypal-cn1lib.html#comment-23306)) + +> Shai Almog says: +> +> Sure. Right click project Codename One -> Codename One Settings -> Extensions. +> +> Also mirrored to [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbraintree-paypal-cn1lib.html) + + +### **salah Alhaddabi** — June 15, 2017 at 6:54 am ([permalink](https://www.codenameone.com/blog/braintree-paypal-cn1lib.html#comment-23395)) + +> salah Alhaddabi says: +> +> Dear Shai, +> +> I have quoted the followings from PayPal Mobile SDK developer site: +> +> “In countries where Braintree Direct is not available, or to access other features of the PayPal REST API from a mobile app, the native libraries of the PayPal Mobile SDKs enable you to build fast, responsive apps” +> +> it also states that “You can use PayPal’s SDKs in any country where PayPal is accepted”. +> +> So the PayPal Mobile SDKs are accepted in more countries including my country “Oman”. +> +> is the CN1 library built using PayPal Mobile SDKs ?? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbraintree-paypal-cn1lib.html) + + +### **Shai Almog** — June 16, 2017 at 6:59 am ([permalink](https://www.codenameone.com/blog/braintree-paypal-cn1lib.html#comment-24206)) + +> Shai Almog says: +> +> Hi, +> it will fallback to paypal. The location restriction is for the payment receiver. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbraintree-paypal-cn1lib.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/build-app-beta.md b/docs/website/content/blog/build-app-beta.md new file mode 100644 index 0000000000..181404a370 --- /dev/null +++ b/docs/website/content/blog/build-app-beta.md @@ -0,0 +1,39 @@ +--- +title: Build App Beta +slug: build-app-beta +url: /blog/build-app-beta/ +original_url: https://www.codenameone.com/blog/build-app-beta.html +aliases: +- /blog/build-app-beta.html +date: '2018-10-09' +author: Shai Almog +--- + +![Header Image](/blog/build-app-beta/codename-one-build.jpg) + +One of the big “behind the scenes” motivations for our big [build cloud migration](https://www.codenameone.com/blog/new-build-cloud.html) was new server API’s. We now have a completely new backend and this made it easier to build a completely new Codename One App christened as “Codename One Build”. + +This app is currently in public beta on Android which you can opt-into [here](https://play.google.com/apps/testing/com.codename1.build.app). Once we feel good with the Android version we’ll push out versions for iOS and maybe UWP if there’s demand for that. + +To keep things simple we are currently focusing on the bare minimum so we can build on top of that. Furthermore, it’s at version 0.13 so it’s far from production grade. But it works really well and should be instantly useful for all of us. It includes several interesting features: + + * Push notifications on builds + + * Essentially eliminates the need of using the website for build tracking + + * Ability to subscribe using In-App-Purchase – this is highly experimental so if you run into a problem let us know! + +__ | We made the app beta to get it out as soon as possible but for all intents and purposes this is Alpha level software +---|--- + +We have big plans for this app and have some pretty interesting ideas for it as we move forward. Right now we want to focus on the core functionality so it runs as smoothly as possible. As it matures we might use this app as the basis for a new web UI as well. + +We plan to push frequent updates to this app and refine it as we go. So we need your help with issues which you can file in the [usual place](http://github.com/codenameone/CodenameOne/issues/). + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/build-app-not-coming-ios.md b/docs/website/content/blog/build-app-not-coming-ios.md new file mode 100644 index 0000000000..c8205d1f02 --- /dev/null +++ b/docs/website/content/blog/build-app-not-coming-ios.md @@ -0,0 +1,77 @@ +--- +title: The Native Version of Build isn't Coming to iOS +slug: build-app-not-coming-ios +url: /blog/build-app-not-coming-ios/ +original_url: https://www.codenameone.com/blog/build-app-not-coming-ios.html +aliases: +- /blog/build-app-not-coming-ios.html +date: '2019-03-26' +author: Shai Almog +--- + +![Header Image](/blog/build-app-not-coming-ios/codename-one-build.jpg) + +When we [released Codename One 6.0](https://www.codenameone.com/blog/codename-one-6-0-chat-live.html) we mentioned that Codename One build is going through the approval process on iOS. We didn’t mention that this was a process where Apple repeatedly rejected us and we had to appeal over and over again. + +We wanted to have a native app because they look/feel slightly better. We also wanted native in-app-purchase as an alternative to PayPal. But it seems Apple won’t allow a native app to do basic things that a web app can easily pull off on its platform. + +For iOS we had to hide the fact that builds can exist for other OS’s. So we can’t mention Android support or even show the logo. That’s prohibited by Apples terms. But the sticking point was the ability to install the app you built. A pretty basic feature for an app building service. It works for web apps without a problem, we just launch a link and the app installed. + +It seems that Apple guideline 2.5.2 prohibits 3rd party app installations. This makes a lot of sense on the surface. It’s meant to stop spam applications from constantly pushing you to install additional apps or stop a hacker from leveraging a loophole. But this is a legitimate use that works on the web and it’s crucial for this type of app. In a sense these guidelines make native apps less powerful than their web based equivalents. + +After spending ages back and forth with Apples bureaucrats over this requirement it seems that this just won’t happen. But I also had an epiphany of sort… + +### Web is Sometimes Better + +I’m strongly in the “native first” camp as this is our core business: we sell a cross platform native development tool. While it supports targeting web UI’s as well, that’s a secondary function and not its primary value. + +However, in this specific case, Apples restrictions make no sense. Amazingly, web provides the same level of functionality as the native app. It also has a couple of other advantages: + + * Fast/instant deployment + + * No restrictions about mentioning other platforms + + * Subscriptions – Without the “Apple tax” + +The disadvantages for our case are: + + * No appstore discoverability - This isn’t a big deal as there are so many apps in the stores today + + * No in-app-subscriptions - This is a benefit and a curse. In app purchase is a “low touch” solution for subscriptions but the cost and restrictions are prohibitive + + * No push – This is the most painful downside of this, it seems all browsers on iOS don’t support push at this time + +Another disadvantage is the seamless login support. We invoke the app with a token from the web in order to login without a password. That’s both secure and convenient as one doesn’t need to type a password on the device. + +This is problematic for the web app and as a result we need to show a typical email/password box. That’s not a deal breaker but it’s still a slight annoyance. + +### Do We Still Need Native? + +Not as much as we used to and this gap is eroding fast. There are still annoyances with small things that are trivial to accomplish in native but require multiple steps in the web version. But for the most part they are easy to circumvent. + +One of the nice things about cross platform development is the fact that we don’t rely on Apples whims. We can just release the web version of the app and keep working. That’s a huge advantage. It’s still not perfect but it looks as close as possible to a native app even though it’s technically a web app. So for this particular case this can work. + +For the Android version we still have the native app that works just fine. It also looks slightly better than the web version on the same device (mostly due to fonts). It supports push and in-app-purchase so it provides that full app experience. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — March 31, 2019 at 8:13 am ([permalink](https://www.codenameone.com/blog/build-app-not-coming-ios.html#comment-23958)) + +> Francesco Galgani says: +> +> Dear Shai, +> I understand the problem: I have an app with high votes on Android (4.8/5) and +1000 installations, but Apple rejected the same identical app multiple times because the reviewers consider it “useless”… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-app-not-coming-ios.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/build-app-on-ios.md b/docs/website/content/blog/build-app-on-ios.md new file mode 100644 index 0000000000..15279bb5fc --- /dev/null +++ b/docs/website/content/blog/build-app-on-ios.md @@ -0,0 +1,26 @@ +--- +title: Build App on iOS +slug: build-app-on-ios +url: /blog/build-app-on-ios/ +original_url: https://www.codenameone.com/blog/build-app-on-ios.html +aliases: +- /blog/build-app-on-ios.html +date: '2018-10-16' +author: Shai Almog +--- + +![Header Image](/blog/build-app-on-ios/codename-one-build.jpg) + +We [launched the Codename One Build App beta on Android last week](/blog/build-app-beta.html) and now we have a public beta for iOS as well. You can sign up to join the public beta through [this link](https://testflight.apple.com/join/Y3RxSm81). Notice that you will need testflight on your device to join the public beta test. + +As is the case with the Android version please let us know if there are issues you experience in the [issue tracker](http://github.com/codenameone/CodenameOne/issues/). The app mostly “just worked” on iOS but getting through the approval and submission process is always a pain. As part of that work we also improved the tablet UI which makes the app very usable on the iPad. + +We’re refining the app further and hopefully we’ll bring it to production grade soon. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/build-apps-with-java-for-ios-android-tutorials-resources.md b/docs/website/content/blog/build-apps-with-java-for-ios-android-tutorials-resources.md new file mode 100644 index 0000000000..83ea693d38 --- /dev/null +++ b/docs/website/content/blog/build-apps-with-java-for-ios-android-tutorials-resources.md @@ -0,0 +1,129 @@ +--- +title: Tutorials & Resources – Build Apps with Java for iOS, Android etc +slug: build-apps-with-java-for-ios-android-tutorials-resources +url: /blog/build-apps-with-java-for-ios-android-tutorials-resources/ +original_url: https://www.codenameone.com/blog/build-apps-with-java-for-ios-android-tutorials-resources.html +aliases: +- /blog/build-apps-with-java-for-ios-android-tutorials-resources.html +date: '2016-09-27' +author: Shai Almog +--- + +There are many Codename One resources for building native mobile apps but they are often all over the place, in this blog post I’ll try to concentrate the best resources for people who already know Java and are looking to pick up Codename One. If you don’t know Java yet, please check out [this post](/blog/codapps-io-is-back-java-on-mobile-from-scratch.html) where we discuss resources for beginners to learn Java. + +### Written Docs and Tutorials + + * [• Create an Uber Clone in 7 Days](https://uber.cn1.co/) – Even if you don’t purchase the full book, the free chapters available to download will help you get started quickly. + * * [• Developer Guide](https://www.codenameone.com/manual/) – if you haven’t read the developer guide you should! Notice that it also comes in a [PDF](https://www.codenameone.com/files/developer-guide.pdf). + * * [• JavaDocs](https://www.codenameone.com/javadoc/) – our JavaDocs include some hidden features such as the [component gallery](https://www.codenameone.com/javadoc/com/codename1/ui/package-summary.html) & [layout gallery](https://www.codenameone.com/javadoc/com/codename1/ui/layouts/package-summary.html). + * * [• Sviluppare app multipiattaforma – Indice del corso introduttivo](https://www.informatica-libera.net/content/sviluppare-app-multipiattaforma-indice-del-corso-introduttivo) – Italian language free course for mobile cross-platform development by Francesco Galgani. + * * [• Port an Android app to iOS (iPhone)](/blog/port-native-android-app-ios-iphone-guide.html) – a step by step guide on porting a real world Android app to Codename One and getting it onto all the major stores. + * * [• Chat App Tutorial](/blog/building-a-chat-app-with-codename-one-part-1.html) – this six part series covered many ideas in Codename One including social login (Facebook, Google) IM style interface etc. + * * [• Using the new GUI Builder](/blog/using-the-new-gui-builder.html) – this tutorial starts by reviewing the differences between the old and the new GUI builder followed by a review of building a simple app. + * * [• Working with native maps](/blog/new-improved-native-google-maps.html) – using Google Maps in your app. + * * [• PSD to App Revisited](/blog/psd-to-app-revisited.html) – this is a remake of a great video tutorial from Steve Hannah (see below) where he covered the process of taking a Photoshop PSD design and making the app look like the PSD. The results are **stunning**. + * * [• Integrating 3rd party native SDK’s](/blog/integrating-3rd-party-native-sdks-part-1.html) – this is one of our most ambitious tutorials it included 3 parts. [Part 1](/blog/integrating-3rd-party-native-sdks-part-1.html), [part 2](/blog/integrating-3rd-party-native-sdks-part-2.html) & [part 3](/blog/integrating-3rd-party-native-sdks-part-3.html). + * * [• Websocket Support](/blog/introducing-codename-one-websocket-support.html) – this tutorial covers the cn1lib for websockets + * * [• Create a Gorgeous Sidemenu](/blog/tutorial-create-a-gorgeous-sidemenu.html) – 5 minute video & text tutorial on the creation of a good looking side navigation interface. + * * [• Introduction to In-App Purchase](/blog/intro-to-in-app-purchase.html) – this is a part of a series on in-app-purchase covering also [Non-Renewable Subscriptions](/blog/in-app-purchase-non-renewable-subscriptions.html) & [Auto-Renewing Subscriptions.](/blog/autorenewing-subscriptions-in-ios-and-android.html) + * * • [Connecting to a MySQL Database from Codename One](/blog/connecting-to-a-mysql-database-part-2.html) – includes two versions the [second](/blog/connecting-to-a-mysql-database-part-2.html) uses Java on the server side while the [first](/blog/connecting-to-a-mysql-database.html) uses a PHP backend and is arguably simpler to setup on the server for some cases. + * + + * [• Using Icon Fonts Such as Fontello](/blog/using-icon-fonts-such-as-fontello.html) – in this tutorial we review icon font usage in Codename One. These are very useful for resolution independent images. + * * [• Avoiding Lists](/blog/avoiding-lists.html) – A common question is how to use a “List” in Codename One. In this tutorial we explain why lists in Codename One are problematic and the strategies you can use to create a list interface. + * * [• Understanding the Table Component](/blog/understanding-the-table-component.html) – this tutorial is pretty self explanatory. + * * [• Understanding device density](/blog/i-am-your-density.html) – in a tutorial written for “back to the future day” Steve covers the nuances of device densities. + * * [• CSS Support](/blog/rounded-corners-shadows-and-gradients-with-css.html) – in this tutorial Steve talks about the CSS support he built for Codename One. There is also a [followup article on new CSS capabilities.](/blog/using-css-to-import-images.html) + * * [• Dynamic Autocomplete](/blog/dynamic-autocomplete.html) – in this tutorial we discuss the usage of an auto-complete text field and how we can use a webservice to provide suggestions to users. + * * [• Local notifications on iOS & Android](/blog/local-notifications.html) – covered the support for firing local notifications when the app is in the background. + * * [• Deploy the same app multiple times](/blog/deploy-same-mobile-app-template-multiple-times.html) – in this short tutorial we cover the process of making an app template that you can redeploy e.g. to sell similar apps to multiple customers or build a demo/release version. + * * [• Building Cloud-powered Native Mobile Apps with Parse.com](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.html) – while parse was discontinued, parse4cn1 is still going strong with 3rd party parse alternatives. + * * [• Shrinking sizes & optimizing](/blog/shrinking-sizes-optimizing.html) – how to reduce your application size. + * * [• Automating releases](/blog/automating-releases.html) – this post covers the enterprise grade continuous integration support. + * * [• JQuery style selectors](/blog/jquery-css-style-selectors-for-cn1.html) – use selectors to manipulate specific components. + * * [• Setup a Codename One Project from Git](/blog/tip-setup-codename-one-demo-from-git.html) – covers the process of converting a git project to a local project. + * + +There are many other tutorials, too many to list, you can see some of them in the [How Do I?](https://www.codenameone.com/how-do-i.html) and that is still a partial list as it doesn’t cover the older posts from before the site migration. + +### Videos & Online Courses + +Notice that a while back, we shifted most of our effort to the Codename One Academy. Some of the older videos below might be out of date. + + * * [• Codename One Academy](https://debugagent.com/series/cn1) – contains both free and premium courses covering almost everything there is to know in Codename One and the tools to build full featured apps. + * * [• Hello world video tutorial](https://youtu.be/rl6z7DD2-vg) – video covering the steps of building/running a Codename One app. + * * [• Todo Video Tutorial](https://youtu.be/cnEyFYbdrRo) – Covers Codename One basics by walking you through the basics of building a simple Todo app. + * * [• What is Codename One](https://www.youtube.com/watch?v=MrwbpdMALig) – a thorough walkthrough of Codename One underpinnings, it’s history and how it differs from other approaches to cross platform. + * * [• Learn mobile programming by example](https://www.udemy.com/learn-mobile-programming-by-example-with-codename-one/) – this course walks you thru the source code of the Property Cross & Dr. Sbaitso demos. + * * [• Build mobile iOS apps in Java](https://www.udemy.com/build-mobile-ios-apps-in-java-using-codename-one/) – walks thru the creation of a client/server image sharing app. It covers the creation of a webservice connection to a Java webserver, file upload, camera and many other details. + * * [• How Do I](/how-do-i.html) – this is a large collection of short videos covering everything from layouts to webservices etc. Some aren’t as fresh as the others but the list is pretty comprehensive. + * * [• How to use the Codename One Sources](/blog/how-to-use-the-codename-one-sources.html) – as the name suggests, this tutorial gets you started with running a Codename One app compiled against the Codename One sources from git. + * * [• PSD to APP](/blog/psd-to-app-converting-a-beautiful-design-into-a-native-mobile-app.html) – the original tutorial from Steve took the form of a video webcast. We later updated it in text form but things such as photoshop might be easier to understand in a video. + * * [• Cordova/PhoneGap compatibility](/blog/phonegap-cordova-compatibility-for-codename-one.html) – this isn’t just a video but it covers a lot of the ideas behind the Cordova support we added to Codename One a while back. + * * [• Debug a Codename One app on an Android Device](/blog/debug-a-codename-one-app-on-an-android-device.html) – this is technically a How Do I? video but it’s a really good one so it’s listed here. + * * [• Codename One Webinar](/blog/java-mobile-dev-webinar-recap.html) – Steve did a couple of Codename One webinars, the second one is [here](/blog/java-mobile-dev-webinar-sequel-recap.html). Those were both very interesting and covered multiple different topics. + * * [• Dr. Sbaitso](/blog/dr-sbaitso.html) & [Property Cross](/blog/propertycross-demo.html) – this is effectively the same content as the “by example” course above but on YouTube. + * * [• LTS Talk](https://www.youtube.com/watch?v=dDu8BpsGfPk) – a talk I gave to LTS over cross mobile device programming. + * * [• JavaZone 2013 talk](http://vimeo.com/74440476) – a lecture covering the basic principals of Codename One. + * * [• Lecture from Mateja Opacic](https://www.youtube.com/watch?v=NNYvyNmPDq4) – Mateja gave a lecture at the Coding Serbia Conference and discussed Codename One. + * + +### More? + +We hope to produce more content as we move forward both to replace older/outdated content and to provide more “ready made” starting points. + +Our property cross and chat tutorials were very successful mostly because they represent real world types of applications developers want unlike the kitchen sink which is abstract. + +These tutorials require a lot of time & effort so we don’t get to do as many as we might want. + +If you have thoughts or wishlists for tutorials, we’d be happy to hear about them. Also if you have your own tutorial somewhere, feel free to post a link in the comments, as long as it’s relevant we’ll approve it thru moderation and maybe add it to the post. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Urfi Mirza** — November 3, 2016 at 9:25 am ([permalink](https://www.codenameone.com/blog/build-apps-with-java-for-ios-android-tutorials-resources.html#comment-22988)) + +> Urfi Mirza says: +> +> HI….How can I create a Mobile app using NetBeans 8 Codeone project for Mobile phone deleted file recovery program? or is there any API that I can incude in my project and complete the project…..Thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-apps-with-java-for-ios-android-tutorials-resources.html) + + +### **Shai Almog** — November 4, 2016 at 5:51 am ([permalink](https://www.codenameone.com/blog/build-apps-with-java-for-ios-android-tutorials-resources.html#comment-22954)) + +> Shai Almog says: +> +> Hi, +> mobile phones block low level filesystem access so an app like that will be impractical natively without rooting the device which is problematic even on Android. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-apps-with-java-for-ios-android-tutorials-resources.html) + + +### **Daniel Charlie** — April 21, 2017 at 10:08 am ([permalink](https://www.codenameone.com/blog/build-apps-with-java-for-ios-android-tutorials-resources.html#comment-23410)) + +> Daniel Charlie says: +> +> Interesting topics. nice information helped me a lot. if it possible share some more……….. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-apps-with-java-for-ios-android-tutorials-resources.html) + + +### **Juan Carlos Vásquez** — October 24, 2019 at 6:26 pm ([permalink](https://www.codenameone.com/blog/build-apps-with-java-for-ios-android-tutorials-resources.html#comment-24261)) + +> [Juan Carlos Vásquez](https://lh3.googleusercontent.com/a-/AAuE7mAJOkU7kIqsnkKnwtvNJ-8Z7x7_P2ufePr3WLZuCA0) says: +> +> Hello, can you post a tutorial on how to login to a backend server via MySQL-PHP-JSON? Thank you! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-apps-with-java-for-ios-android-tutorials-resources.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/build-desktop-apps-xml-improvements.md b/docs/website/content/blog/build-desktop-apps-xml-improvements.md new file mode 100644 index 0000000000..a9cc3d047f --- /dev/null +++ b/docs/website/content/blog/build-desktop-apps-xml-improvements.md @@ -0,0 +1,107 @@ +--- +title: Build Desktop Apps & XML Improvements +slug: build-desktop-apps-xml-improvements +url: /blog/build-desktop-apps-xml-improvements/ +original_url: https://www.codenameone.com/blog/build-desktop-apps-xml-improvements.html +aliases: +- /blog/build-desktop-apps-xml-improvements.html +date: '2014-01-12' +author: Shai Almog +--- + +![Header Image](/blog/build-desktop-apps-xml-improvements/build-desktop-apps-xml-improvements-1.png) + + + + + +![Picture](/blog/build-desktop-apps-xml-improvements/build-desktop-apps-xml-improvements-1.png) + + + + +The next plugin update will finally include the support for building desktop applications with Codename One and to celebrate this we added a +[ +How Do I video on this subject +](/how-do-i-use-desktop-javascript-ports.html) +. Notice that this is a pro only feature so if you don’t have a pro account this will fail on the build server. + + +The end result should be pretty similar to what you get in the simulator, I assume we will make some improvements as we move along to refine the user experience a bit further and adapt it for desktop development. + + + + + +We also added support for XML user interface elements in the designer, if you activate team mode in the designer and save the resource file you will now notice that we generate a UI file for every form (as well as a file with no extension which is a binary file). Currently the UI file is write only to prevent issues with this approach from breaking existing usage. However, if you want to move to a more XML based file format right now you would be able to edit your top level XML file and set + +useXmlUI=”false”. + + +Once you change that all changes to the .ui files will be incorporated when + +you reload the resource file and you will be able to work with XML files which might be convenient if you are doing elaborate team work. This is also convenient for the case of a recovery if a file gets corrupted you should be able to recover more easily and see what happened. + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — January 28, 2014 at 4:50 am ([permalink](https://www.codenameone.com/blog/build-desktop-apps-xml-improvements.html#comment-22065)) + +> Anonymous says: +> +> Good article but it should have been a bit more descriptive. Any suggestions for me, I do don’t have a pro account. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-desktop-apps-xml-improvements.html) + + +### **Anonymous** — January 28, 2014 at 5:00 pm ([permalink](https://www.codenameone.com/blog/build-desktop-apps-xml-improvements.html#comment-21991)) + +> Anonymous says: +> +> You can handcode a desktop app by searching for instructions in the discussion forum. Pro subscription has many other benefits. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-desktop-apps-xml-improvements.html) + + +### **Anonymous** — January 30, 2014 at 1:08 pm ([permalink](https://www.codenameone.com/blog/build-desktop-apps-xml-improvements.html#comment-21671)) + +> Anonymous says: +> +> Why? +> +> What am I missing? Why on earth would I want a desktop version of my tablet app? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-desktop-apps-xml-improvements.html) + + +### **Anonymous** — January 30, 2014 at 2:33 pm ([permalink](https://www.codenameone.com/blog/build-desktop-apps-xml-improvements.html#comment-21946)) + +> Anonymous says: +> +> Initially that’s what we thought but users asked for that quite a lot. There are several reasons: +> +> 1\. Demo – this way users can download a demo version to run on their PC/Mac. +> +> 2\. x86 tablets – E.g surface pro etc. have a niche following in some sectors. +> +> 3\. Checklist feature – some developers need a desktop app as a feature but don’t care if it feels like a mobile app. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-desktop-apps-xml-improvements.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/build-hint-variables.md b/docs/website/content/blog/build-hint-variables.md new file mode 100644 index 0000000000..d75f2cc278 --- /dev/null +++ b/docs/website/content/blog/build-hint-variables.md @@ -0,0 +1,76 @@ +--- +title: Build Hint Variables +slug: build-hint-variables +url: /blog/build-hint-variables/ +original_url: https://www.codenameone.com/blog/build-hint-variables.html +aliases: +- /blog/build-hint-variables.html +date: '2016-08-03' +author: Shai Almog +--- + +![Header Image](/blog/build-hint-variables/build-hints.png) + +This is a feature Steve added way back in June but I didn’t get around to documenting it. Build hints can sometimes get “unwieldy” e.g. in the case of `ios.plistInject` or `android.xapplication` we sometimes have pretty verbose values. + +We now have a way to define a “build hint variable” which the build server substitutes seamlessly. This is useful for “key” values required by API’s that sometimes require boilerplate e.g. the [Google Maps support](https://github.com/codenameone/codenameone-google-maps/) has this: + + + android.xapplication= + +Notice that the one thing that actually matters here is `YOUR_ANDROID_API_KEY` which makes this problematic. We can’t add this string to the build hints automatically because this is a value you need to set…​ + +The variables allow us to do this instead: + + + var.androidAPIKey=YOUR_ANDROID_API_KEY + android.xapplication= + +This might seem more verbose but notice that the cn1lib can now inject the second line automatically and you will need to add this single line: `var.androidAPIKey=YOUR_ANDROID_API_KEY` + +That is far simpler than before and less error prone. + +Most cn1libs still don’t take advantage of this syntax but hopefully we’ll move them in that direction as we move forward. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Gareth Murfin** — August 5, 2016 at 12:35 pm ([permalink](https://www.codenameone.com/blog/build-hint-variables.html#comment-22830)) + +> Gareth Murfin says: +> +> Had not even considered this, very useful indeed! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-hint-variables.html) + + +### **Torjmen Hamza** — April 30, 2017 at 12:28 pm ([permalink](https://www.codenameone.com/blog/build-hint-variables.html#comment-23491)) + +> Torjmen Hamza says: +> +> Hello, +> I have problems with Google Maps in Codename One, I tried to make a useful path like DirectionRoute in javascript but it is always a black line, it’s like that i have airlines, could some one help me with that ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-hint-variables.html) + + +### **Shai Almog** — May 1, 2017 at 3:52 am ([permalink](https://www.codenameone.com/blog/build-hint-variables.html#comment-23281)) + +> Shai Almog says: +> +> Hi, +> why not ask that in the maps post [https://www.codenameone.com…]() +> I suggest asking there and mentioning what you did. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-hint-variables.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/build-hints-editor.md b/docs/website/content/blog/build-hints-editor.md new file mode 100644 index 0000000000..31cd29932d --- /dev/null +++ b/docs/website/content/blog/build-hints-editor.md @@ -0,0 +1,229 @@ +--- +title: Build-Hints Editor +slug: build-hints-editor +url: /blog/build-hints-editor/ +original_url: https://www.codenameone.com/blog/build-hints-editor.html +aliases: +- /blog/build-hints-editor.html +date: '2022-03-01' +description: In the latest plugin update, we’ve added a Build-Hints Editor that accessible + from a menu item inside the Codename One simulator. This is intended to make it + easier to edit your app’s build hints, and also inform you of build hints that you + may need to configure. +--- + +In the latest plugin update, we’ve added a Build-Hints Editor that accessible from a menu item inside the Codename One simulator. This is intended to make it easier to edit your app’s build hints, and also inform you of build hints that you may need to configure. + +![codename one - build hint editor](/blog/build-hints-editor/cn1-build-hint-editor-1024x536.jpg) + +Unlike the existing mechanisms for editing build hints (in Codename One Settings, or directly editing the codenameone_settings.properties file), this editor can integrate the requirements of installed cn1libs to help guide you through their configuration. + +> The latest release of the Google Maps cn1lib is the first module to make use of the build-hint editor. If you are developing a cn1lib that requires users to set specific build hints for its proper functioning, then you should follow the instructions in this article to integrate your library into the build hints editor. + +### Usage Instructions + +In order to use the build-hints editor, you should launch your app in the Codename One simulator. + +Once your app is running, select _Tools_ > _Edit Build Hints…​_. + +![](/blog/build-hints-editor/edit-build-hints-menu.png) + +This will launch the build-hints editor in a new window as shown below. + +![](/blog/build-hints-editor/build-hints-editor.png) + +## TIP + +> The "Google Maps" tab appears in the above screenshot because the Google Maps cn1lib is installed in this app. If your app doesn’t use Google Maps, then it won’t include this tab. + +One nice feature of this editor vs using Codename One settings is that some build hints include help text and example content, as well as buttons to perform complementary actions. For example, take a look at the field for the `ios.afterFinishLaunching` build hint: + +![](/blog/build-hints-editor/ios-afterfinishlaunching-fields.png) + +It includes a text field for entering the build hint, some help text to let you know what this build hint is for and some example input to show you the proper format. + +In this case it also includes a “Get Key” button that will open the webpage for creating an API key. + +The old way to set up Google maps was to follow the [README](https://github.com/codenameone/codenameone-google-maps#readme), and look manually walk through the required steps. + +## IMPORTANT + +> You should still read the installation instructions in the README for all cn1libs you are using. The Build-hints editor just provides a simpler way to deal with the build-hints portion of this. + +After making changes to your build hints, press _Apply_ or _Save_. The difference is that _Apply_ won’t close the build-hints editor. _Save_ will. + +### Instructions for CN1lib Developers + +If you are developing a cn1lib that requires users to add custom build hints to their app, consider adding a tab for your cn1lib in the build-hints editor. This can be done by defining some Display properties in your cn1lib. + +## NOTE + +> You can also define java.lang.System properties directly if you are working in JavaSE native code. When running in the simulator, calling CN1.setProperty("foo", "bar") will ultimately call System.setProperty("foo", "bar") under the hood. + +Before I walk through the intricacies of the syntax, let’s look at the [real-world example of the Google Maps library](https://github.com/codenameone/codenameone-google-maps/blob/13da47a7051084e30a1ce8fac0b762b898bfac72/GoogleMaps/javase/src/main/java/com/codename1/googlemaps/InternalNativeMapsImpl.java). + + + + System.setProperty( + "codename1.arg.{{#googlemaps#javascript.googlemaps.key}}.label", + "Javascript API Key" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#javascript.googlemaps.key}}.description", + "Please enter your Javascript API key." + ); + System.setProperty( + "codename1.arg.{{#googlemaps#javascript.googlemaps.key}}.link", + "https://developers.google.com/maps/documentation/javascript/get-api-key Get Key" + ); + + System.setProperty( + "codename1.arg.{{#googlemaps#android.xapplication}}.label", + "android.xapplication" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#android.xapplication}}.description", + "Your android.xapplication build hint must inject your Android API key" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#android.xapplication}}.hint", + "" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#android.xapplication}}.link", + "https://developers.google.com/maps/documentation/android-sdk/get-api-key Get Key" + ); + + System.setProperty( + "codename1.arg.{{#googlemaps#ios.afterFinishLaunching}}.label", + "ios.afterFinishLaunching" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#ios.afterFinishLaunching}}.description", + "Your ios.afterFinishLaunching hint must inject your IOS API Key" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#ios.afterFinishLaunching}}.hint", + "[GMSServices provideAPIKey:@\"YOUR_IOS_API_KEY\"];" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#ios.afterFinishLaunching}}.link", + "https://developers.google.com/maps/documentation/ios-sdk/get-api-key Get Key" + ); + + System.setProperty( + "codename1.arg.{{#googlemaps#android.min_sdk_version}}.label", + "Android Minimum SDK Version" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#android.min_sdk_version}}.description", + "Your Android Minimum SDK Version must be at least 19" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#android.min_sdk_version}}.hint", + "19" + ); + + System.setProperty( + "codename1.arg.{{@googlemaps}}.label", + "Google Maps" + ); + System.setProperty( + "codename1.arg.{{@googlemaps}}.description", + "The following build hints are required for the Google Maps cn1lib to operate correctly." + ); + + + +Allow me to unpack this a little bit. By defining these properties, the build-hints editor will know to generate the appropriate fields for the user to edit these build hints. + +The general syntax is: + + + codename1.arg.{{ BUILD_HINT_NAME }}.PROPERTY_NAME + +where `BUILD_HINT_NAME` is the name of the build hint that this pertains to, and `PROPERTY_NAME` is the specific metadata property that we are setting. + +Some property names that you can define include: + +## label + +The label for this build hint as it will be rendered in the built-hints editor. + +## description + +The help text. A short blurb to let the user know what the build hint is for. + +## hint + +Some example input for this build hint. + +## link + +An optional link to learn more about this build hint, or perform an associated action. This will be rendered as a button next to the help text for the build hint. You can optionally include a label for this button after the URL by leaving a “space” between them. E.g. “http://example.com/foobar Go to Foobar” + +## type + +The widget type to use for editing this build hint. Supported values include “textfield”, “textarea”, “checkbox”, and “select” + +## values + +A list of options to use when the _type_ property is “select”. Values should be delimited by a character, and the delimiter is defined by the trailing character. E.g. `red, green, blue,` or `red; green; blue;`. The import part is that the delimiter is included at the _end_ as the build-hints editor will check the last character to find out what the delimiter is. + +With this in mind, let’s take a look at the `ios.afterFinishLaunching` field settings: + + + + System.setProperty( + "codename1.arg.{{#googlemaps#ios.afterFinishLaunching}}.label", + "ios.afterFinishLaunching" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#ios.afterFinishLaunching}}.description", + "Your ios.afterFinishLaunching hint must inject your IOS API Key" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#ios.afterFinishLaunching}}.hint", + "[GMSServices provideAPIKey:@\"YOUR_IOS_API_KEY\"];" + ); + System.setProperty( + "codename1.arg.{{#googlemaps#ios.afterFinishLaunching}}.link", + "https://developers.google.com/maps/documentation/ios-sdk/get-api-key Get Key" + ); + + + +## NOTE + +> The `googlemaps prefix to the build hint causes the field to be rendered inside its own "Google Maps" tab of the build-hints editor. + +![](/blog/build-hints-editor/build-hint-properties.png) + +### Configuring Custom Tabs + +Notice that the Google maps build hints are all rendered inside a nice “Google Maps” tab. This is accomplished by defining a “googlemaps” group, and then assigning each property to that group. The portion that defines the “googlemaps” group is shown below: + + + + System.setProperty( + "codename1.arg.{{@googlemaps}}.label", + "Google Maps" + ); + System.setProperty( + "codename1.arg.{{@googlemaps}}.description", + "The following build hints are required for the Google Maps cn1lib to operate correctly." + ); + + + +The property name follows the same syntax as for regular properties: “codename1.arg.{{ @GROUP_NAME }}.PROPERTY_NAME”, except that the `GROUP_NAME` here must be prefixed with `@`. This signifies that the property pertains to the group as a whole rather than a particular build hint. + +The second part of ensuring that properties render in the _googlemaps_ group is that the build hint name needs to be prefixed with `GROUPNAME`. In this case it would be `googlemaps`. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube.md b/docs/website/content/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube.md new file mode 100644 index 0000000000..4af7f46ccd --- /dev/null +++ b/docs/website/content/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube.md @@ -0,0 +1,114 @@ +--- +title: Build Mobile iOS Apps In Java Using Codename One On Youtube +slug: build-mobile-ios-apps-in-java-using-codename-one-on-youtube +url: /blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube/ +original_url: https://www.codenameone.com/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube.html +aliases: +- /blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube.html +date: '2014-08-31' +author: Shai Almog +--- + +![Header Image](/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube/hqdefault.jpg) + + + +This material is out of date by now. We recommend checking out the [Codename One Academy](/blog/launching-codename-one-academy.htmls). + +We’ve uploaded the full course video cast as a youtube playlist, just go thru the parts and in an hour and some change you should understand the basics of creating a simple Codename One client server application that runs on all mobile devices. + + +The Udemy course is +[ +still there +](https://www.udemy.com/build-mobile-ios-apps-in-java-using-codename-one/) +and probably useful if you live in a region where youtube is blocked. The source code to accompany the course can be viewed in SVN here: + + +[ +https://code.google.com/p/codenameone/source/browse/trunk/Demos/PhotoShare/ +](https://code.google.com/p/codenameone/source/browse/trunk/Demos/PhotoShare/) + + + +For your convenience you can also download the projects as a zip + + + + + + + + + + +[ +__Download +](/files/photoshare.zip) + +* * * + +To learn more about Codename One we suggest checking out our +[ +getting started page +](/getting-started.html) +. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — October 9, 2014 at 7:24 am ([permalink](https://www.codenameone.com/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube.html#comment-22174)) + +> Anonymous says: +> +> Hello Shai, +> +> I want to follow this tutorial but I am not sure if it is only for iOS or can also be ussed for android. +> +> Thank you +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-mobile-ios-apps-in-java-using-codename-one-on-youtube.html) + + +### **Anonymous** — October 9, 2014 at 1:21 pm ([permalink](https://www.codenameone.com/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube.html#comment-21604)) + +> Anonymous says: +> +> Yes its for all platforms. The main reason for iOS in the title is the mindshare/SEO aspect of this but its applicable for everything. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-mobile-ios-apps-in-java-using-codename-one-on-youtube.html) + + +### **Ankit Mathur** — April 7, 2015 at 9:30 am ([permalink](https://www.codenameone.com/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube.html#comment-22071)) + +> Ankit Mathur says: +> +> Its all working perfectly… But still I have two questions. +> 1\. How to change the form programmatically? +> 2\. Can we use the JAR files to create some graphs / some drawings / capture locations as in android. and many more devices. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-mobile-ios-apps-in-java-using-codename-one-on-youtube.html) + + +### **Shai Almog** — April 7, 2015 at 7:21 pm ([permalink](https://www.codenameone.com/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube.html#comment-22228)) + +> Shai Almog says: +> +> Check out additional examples that would answer your questions here: [https://www.udemy.com/learn…]() +> 1\. Wasn’t this demonstrated in the demo? [form.show]() etc.? +> 2\. You can use cn1libs: [http://codenameone.com/cn1l…]() Notice that graphs are builtin to Codename One: [http://www.codenameone.com/…]() as is location support etc. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-mobile-ios-apps-in-java-using-codename-one-on-youtube.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/build-native-interfaces-module-camera-edition.md b/docs/website/content/blog/build-native-interfaces-module-camera-edition.md new file mode 100644 index 0000000000..330cd4d034 --- /dev/null +++ b/docs/website/content/blog/build-native-interfaces-module-camera-edition.md @@ -0,0 +1,26 @@ +--- +title: Build Native Interfaces – Camera Edition +slug: build-native-interfaces-module-camera-edition +url: /blog/build-native-interfaces-module-camera-edition/ +original_url: https://www.codenameone.com/blog/build-native-interfaces-module-camera-edition.html +aliases: +- /blog/build-native-interfaces-module-camera-edition.html +date: '2018-04-03' +author: Shai Almog +--- + +![Header Image](/blog/build-native-interfaces-module-camera-edition/deep-dive-into-mobile.jpg) + +I discussed the new [Camera cn1lib last week](/blog/camerakit-low-level-camera-api.html). One of the motivations for doing it (besides the request from an enterprise account) was that of a new course module. Last week I added a [new module](https://codenameone.teachable.com/p/deep-dive-into-mobile-development-with-codename-one) covering the process of building the camera cn1lib…​ +We have several online videos (both in the course and outside of it) covering native interfaces. So why do we need another one? + +Working with native code is error prone & complex. A lot of the tutorials we built in the past ended up spending more time on configuration issues than on code. +In this module I talked a lot about Objective-C, callbacks, delegates & more. If you are thinking about native integration this helps give a more rounded view of the options. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/build-something-big.md b/docs/website/content/blog/build-something-big.md new file mode 100644 index 0000000000..1c433a012b --- /dev/null +++ b/docs/website/content/blog/build-something-big.md @@ -0,0 +1,314 @@ +--- +title: Build Something Big +slug: build-something-big +url: /blog/build-something-big/ +original_url: https://www.codenameone.com/blog/build-something-big.html +aliases: +- /blog/build-something-big.html +date: '2017-03-07' +author: Shai Almog +--- + +![Header Image](/blog/build-something-big/full-stack-java-bootcamp.jpg) + +__ | It’s LIVE! Check out the bootcamp signup [here](https://codenameone.teachable.com/p/full-stack-java-mobile-app-bootcamp/). +---|--- + +I’m going to build a new mobile startup within 2 weeks and teach some of you how that is done while doing that. Most people might assume I’m talking about one of those “MVP” cardboard startups…​ This isn’t the case! +We’ll build a real ground breaking app with a server component that handles storage, push and a few other things you wouldn’t expect and I plan to fit the whole thing in a two week time frame. + +This is essentially what I said in the [last two](https://www.codenameone.com/blog/full-stack-java-bootcamp.html) posts [in this series](https://www.codenameone.com/blog/spring-template-more-about-bootcamp.html). We’ll build the **full stack** of a real world startup from the ground up to server and client production within 2 weeks of hard work! + +Famous last words? + +Over the past 20+ years I worked for startups, major software/hardware companies, operators, banks and much more…​ I founded 4 companies during this time and every time I did it the process became easier. Codename One is a huge product so it’s not something I would compare to “an app”. However, the basic product we launched as beta took 3 months to build and we spent too much of that debating the “launch slide deck”. + +Unlike that effort, building an app is almost trivial when you know how…​ The server side will be relatively simple as it won’t include the web interface portions that are always a pain. Just very basic storage, push and simple management. + +The big effort that will take most of the time is making the apps look good and applying a compelling design. + +With this bootcamp I want you to see how easy it is to build a startup and a complex mobile app. But the bigger goal is to flip a switch within you that would hopefully be as transformational for you as it would be for me. I want to recreate the startup experience as part of the bootcamp, that’s something you can’t do in a course. +Every startup I worked at even as a consultant had affected me on an emotional level and I hope this will leave you in a similar energized state and motivated to “take on the world”. + +### How will this Work? + +At a birds eye view the bootcamp will include a short “getting ready” period for those unfamiliar with Codename One followed by 1 week of basics, 2 weeks of app building hack race and 1 week of finishing, loose ends and cleanup so we are all at the finish line together. + +The whole bootcamp will last 4 work weeks (5 day weeks). The 4 weeks will be divided into 2 week batches so we’ll have 2 intensive weeks followed by a week and a half off to regroup and the second part. + +The bootcamp will start on March 27th and the first two weeks will end on April 6th. + +It will resume on Tuesday April 18th and will end on Monday May 1st. + +Hours for the 1 on 1 sessions will be scheduled individually ideally before the start of the bootcamp for the first session. Since they are 1 on 1 sessions hours would be flexible. + +The course will include: + + * 1 on 1 sessions with each participant. Ideally 2 sessions per participant but logistics of time and number of participants might make scheduling difficult (I’m limiting registration numbers so ideally 2 sessions should fit) + + * Most of the material will be passed as a combination of video and/or webinars. I’ll determine the ratio of video to webinar based on participation and what works for the group + + * Tasks delivered daily – to make best use of the bootcamp I’ll send out individual daily “missions”, those will fit into the puzzle as we continue learning. If an individual mission is too challenging use the chat to get help. + + * We’ll have group chat and a Facebook group for questions/collaboration + +__ | If we will have webinars they will be recorded so if you miss them you will be able to watch them later and ask followup questions via the chat/facebook +---|--- + +The schedule of the course will be as follows: + + * **Pre course** – developers who don’t have Codename One experience will take a small crash course in some of the basics of Codename One so we can begin at an equal footing. This will include some pre-made videos and a few missions to get them ready + + * **Week 1** – Basics: Layouts, theming, portability, density, basic design principles, GUI builder vs. handcoding, animations/transitions, storage, SQLite, networking, threading, EDT, custom components, certificates & signing + + * **Week 2** – Deeper into the core of Codename One and beginning of building the app we will build thru the course, initial server setup with client/server communication (websockets/webservices) + + * **Week 3** – App completion and refinement. Server initiated push, complete design both in CSS & designer, integrating native code + + * **Week 4** – Loose ends – security, store upload, localization/internationalization, performance, on device debugging + +A bootcamp is a very fluid process and is subject to change based on feedback from the group. So if we have a group that needs to spend more time on basics we’ll do that and if the group can run faster we’ll add more material based on demand. + +### One Time Thing + +The way I see this bootcamp it can go in two ways: + + * A lot of people will signup and fill it up completely – this would mean I would have too much work and won’t want to do this again as I need to focus on Codename One + + * Few people will signup – I won’t repeat something that didn’t succeed + +Either way this is probably the only chance to get this bootcamp. + +I’m limiting the seats because if we have too many participants this might get out of hand, we’ll also limit the signup window to 5 days because we need the list of students ASAP. Some students might not know Codename One yet in which case they will need to do a pre-session so the speed of the class won’t be hindered. + +### Signup + +We don’t have the signup page up yet but we’re working on that! + +I’ll send out an e-mail on 2pm GMT this Monday with signup details. It might be ready sooner but I got some feedback that some of you might need time to seek management approval and I wanted to give you the time to do so. However, I can’t give a lot of time here since we are in a rush and the signup needs to finish with time to spare before the bootcamp starts. + +Signup will last until Friday afternoon (GMT) and will close at that point, I’m limiting the number of students significantly so it’s possible we’ll run out of space sooner. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Dalvik** — March 8, 2017 at 7:17 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23106)) + +> Dalvik says: +> +> Looks great! +> I still have three questions after reading this: +> – Price? +> – What would the app be? +> – What sort of availability will we need during the bootcamp? Can I still go to work? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Shai Almog** — March 8, 2017 at 7:44 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23120)) + +> Shai Almog says: +> +> – We’ll list it on Monday +> +> – I’ll reveal this only after the bootcamp starts and only to the team. This will be an actual startup that we will launch and try to get traction for. +> +> – I would be spending the whole day on this during the bootcamp but I’m assuming I would work much harder on this than you guys would. You might be able to get away with half a days work but if you have the ability to take the whole day off and focus on this it might be best as the context switch might be difficult. +> +> I can’t really tell how hard it will be for each of you since this is a bit different from courses I gave in the past and would be more fluid. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Chidiebere Okwudire** — March 8, 2017 at 9:21 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-21566)) + +> Chidiebere Okwudire says: +> +> Are you saying each participant would need to put in roughly half a day per day over the 5-week period? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Shai Almog** — March 8, 2017 at 9:25 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23298)) + +> Shai Almog says: +> +> 4 weeks but generally yes. That’s the difference between a bootcamp and a course. You actually need to do work and learn in a very intense way. +> +> I think people can still get a lot if they don’t put that amount of time but if you look at the post, the goals are pretty intense. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Dalvik** — March 9, 2017 at 4:31 am ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23056)) + +> Dalvik says: +> +> Thanks, that makes sense. I have some Codename One experience and good server experience so I’m guessing this will be less of an effort right? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Shai Almog** — March 9, 2017 at 4:45 am ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23304)) + +> Shai Almog says: +> +> Yes in that case you can get away with less time and possibly multi-tasking. +> +> My point is that the timeline of the bootcamp is helpful. The materials will still be there after the completion of the bootcamp but we might not. So if we finish the bootcamp and you didn’t pay attention then you decide to go back and review stuff it might be a bit harder. You could ask us (I’ll setup a private Facebook Group for discussion) and we’ll try to help but that might impact the learning experience. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **salah Alhaddabi** — March 9, 2017 at 8:34 am ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23046)) + +> salah Alhaddabi says: +> +> Dear Shai, I wish you would have mentioned the time each session will take during the day (greenwich time) and the pricing so we can make up our mind over the weekend before signing up starts. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Shai Almog** — March 9, 2017 at 9:00 am ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23435)) + +> Shai Almog says: +> +> Thanks. +> The times are flexible as we might not have live sessions and even if we do they will be recorded so you can watch them at your convenience. I like live sessions but they might not be practical, I did webinars with some audiences where this worked great and some where it didn’t. It’s hard to know what will work for the group as a whole. +> +> Normally I like pricing upfront so I get where you are coming from. The opacity here is a “hack” from a friend. He explained it so beautifully, I hope I’m not murdering his explanation as I’m not a marketing guy: +> +> Say you have a price up front. People will view everything in your offering in light of your price. E.g a 500 dollar product is clearly inferior to a 5000 dollar product. Even if we KNOW better it’s one of those deeply held mind biases: expensive is more valuable. +> +> Pricing is like that, it’s subjective (cheap for X might be expensive for Y) so the moment you mention a price you are ranked based on everything out there in the market as cheap or expensive and this deters your ability to convey your message of your real value proposition. +> +> I’m in a dilemma here. I need to price things high enough so you will assign value and low enough because I know some of the community is price sensitive but I don’t want to deter from the value proposition that’s discussed. +> +> You need to make an objective decision unrelated to the price tag, decide how much you are willing to pay. When we publish the price it can either be higher or lower. +> +> If it’s lower then you landed a great deal! +> +> If it’s higher then I either overpriced or the value isn’t there for you. +> +> Overall this is better for both of us, you can make an objective decision without the biases that pricing provides. +> +> It’s even a nice consumer hack detailed here: [http://twocents.lifehacker….]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Chad Elofson** — March 9, 2017 at 5:00 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23246)) + +> Chad Elofson says: +> +> Shai, +> +> I definitely won’t determine the value of this bootcamp based on the price. I have worked on a Codename One mobile app and would love to improve my workflow through this bootcamp. +> +> As I am going into business for myself, I would find it helpful if there was a payment option for the bootcamp. Definitely looking forward to Monday! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Chad Elofson** — March 9, 2017 at 5:10 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23388)) + +> Chad Elofson says: +> +> For payment options, I mean having the option to pay it all up front or making two or three payments. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Shai Almog** — March 9, 2017 at 5:47 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-24129)) + +> Shai Almog says: +> +> Thanks! +> +> Since the bootcamp starts this month and ends at the end of next month we won’t have payment options other than a single payment. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Chad Elofson** — March 9, 2017 at 5:51 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23169)) + +> Chad Elofson says: +> +> Then I shall find a way to get it covered. Thanks for the update +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **faenze e.** — March 9, 2017 at 7:16 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-21572)) + +> faenze e. says: +> +> So we can sign up just to see the price, scoff, and cancel? If you are worried about apparent value, how about a sliding scale, since value is relative. 😉 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Shai Almog** — March 9, 2017 at 7:49 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23178)) + +> Shai Almog says: +> +> Nope. The product isn’t launched so you have nothing to signup for. On Monday the bootcamp signup will launch and the price will be there. +> Pricing is relative to you as the payer, not to me as the service provider who has to take nearly two months off work to setup and run this thing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **faenze e.** — March 9, 2017 at 8:16 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23029)) + +> faenze e. says: +> +> Ah, I misinterpreted the signup date and comments. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Andrew Nyago** — March 14, 2017 at 5:09 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23270)) + +> Andrew Nyago says: +> +> Hello, am I late for registration? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Shai Almog** — March 14, 2017 at 6:13 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-21568)) + +> Shai Almog says: +> +> No. When registration closes we will block the ability to process the payment. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Andrew Nyago** — March 15, 2017 at 3:44 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23362)) + +> Andrew Nyago says: +> +> i failed to see the link to the registration page. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + + +### **Shai Almog** — March 15, 2017 at 4:28 pm ([permalink](https://www.codenameone.com/blog/build-something-big.html#comment-23370)) + +> Shai Almog says: +> +> I edited the post after it went live and added it to the top, it’s also in the home page below the fold: [http://codenameone.teachabl…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuild-something-big.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/building-a-chat-app-with-codename-one-part-1.md b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-1.md new file mode 100644 index 0000000000..55f9b84a31 --- /dev/null +++ b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-1.md @@ -0,0 +1,257 @@ +--- +title: 'Tutorial: Building A Cross Platform Mobile Chat App for Android, iOS (iPhone) + With Codename One Part I' +slug: building-a-chat-app-with-codename-one-part-1 +url: /blog/building-a-chat-app-with-codename-one-part-1/ +original_url: https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html +aliases: +- /blog/building-a-chat-app-with-codename-one-part-1.html +date: '2015-07-14' +author: Shai Almog +--- + +![Header Image](/blog/building-a-chat-app-with-codename-one-part-1/chat-app-tutorial-part1.png) + +In this tutorial we will cover the basics of building a good looking chat application with Codename One that +will work on all mobile OS’s. We will cover everything from design to social network login and the actual +chat behavior. This tutorial is for a hand coded application mostly because GUI builder tutorials require video +and are thus less searchable. + +This project is created with the new Java 8 support to make the code simple and short. + +## Creating The New Project + +We create a new Codename One project and select the new flat blue theme. + +![New Project](/blog/building-a-chat-app-with-codename-one-part-1/chat-app-tutorial-part2.png) + +![Theme](/blog/building-a-chat-app-with-codename-one-part-1/chat-app-tutorial-part3.png) + +Once finish is clicked we have a new project in place, so we need some files to get started. First place the file +[fontello.ttf](/files/fontello.ttf) in the src directory. This font file contains image font icons which we will +use to provide icons in the UI. + +Next you will need to save [this image](/files/social-chat-tutorial-image.jpg) to your hard drive for use in the first form. + +## Login UI + +Now that we have all the rest in order its time to launch the designer by double clicking the theme file. In the designer +we need to click the `Images→Quick Add Multi Images` option, then select the [image you downloaded to the disk](/files/social-chat-tutorial-image.jpg). + +When prompted leave the default of `Very High`, this will effectively create a multi image which stores the image +in multiple different resolutions and deliver the properly sized image based on the device density at hand. + +Now we can just create the main form which is the entry point to the app, this will end up looking as such: + +![Final Result](/blog/building-a-chat-app-with-codename-one-part-1/chat-app-tutorial-part4.png) + +To achieve this we select the main theme and click the add button to add a new entry. We then type in `MainForm` +in the top area and design the form: + + * In the first tab we uncheck ‘derive’ and select the type as `IMAGE_SCALED_FILL`. This effectively means we will +use an image as the background and scale it across the screen. We also make sure to select the multi image that +we just added. + + * In the Derive tab we uncheck `derive` (slightly confusing), then select `Form` in the combo box. This means that the +`MainForm` style inherits the basic settings from the Form style. + +Add another UIID called Padding so we can space the buttons away from the sides/bottoms of the form: + + * In the color tab uncheck the `Derive Transparency` and set the value to 0. This will make the container invisible. + + * In the padding section uncheck `derive` and enter 2 millimeters for all entries except for the bottom where we need 8 millimeters for extra spacing. +This will space out the various pieces, its important to use millimeters otherwise the result will be too different on various devices based +on their density. + +![MainForm UIID Styling](/blog/building-a-chat-app-with-codename-one-part-1/chat-app-tutorial-part5.png) + +### Initial Code + +In the code we open the main `SocialChat` class and replace the start method with this: + + + public void start() { + if(current != null){ + current.show(); + return; + } + showLoginForm(); + } + + private void showLoginForm() { + Form loginForm = new Form(); + + // the blue theme styles the title area normally this is good but in this case we don't want the blue bar at the top + loginForm.getTitleArea().setUIID("Container"); + loginForm.setLayout(new BorderLayout()); + loginForm.setUIID("MainForm"); + Container cnt = new Container(new BoxLayout(BoxLayout.Y_AXIS)); + cnt.setUIID("Padding"); + Button loginWithGoogle = new Button("Signin with Google"); + Button loginWithFacebook = new Button("Signin with Facebook"); + cnt.addComponent(loginWithGoogle); + cnt.addComponent(loginWithFacebook); + loginWithGoogle.addActionListener((e) -> { + doLogin(GoogleConnect.getInstance()); + }); + loginWithFacebook.addActionListener((e) -> { + doLogin(FacebookConnect.getInstance()); + }); + loginForm.addComponent(BorderLayout.SOUTH, cnt); + loginForm.show(); + } + + void doLogin(Login lg) { + // TODO... + } + +You will end up with something that looks like this: + +![Basic styling](/blog/building-a-chat-app-with-codename-one-part-1/chat-app-tutorial-part6.png) + +To get the buttons to the right color we and add the icons we will need to go back to the designer…​. + +### Customizing The Buttons + +Lets start with the icons, since we use an icon font this is pretty easy…​ Just add a new style UIID to the theme called +`IconFont`. + + * In the color section click `Derive Foreground` and type in `ffffff` to set the foreground to white, then click +`Derive Transparency` and set it to zero. + + * In the Font tab uncheck the `Derive` flag and select the `fontello.ttf` font (make sure you downloaded it and placed it +in the src directory as instructed earlier). Select the `True Type Size` as Large. + +![Icon Font](/blog/building-a-chat-app-with-codename-one-part-1/chat-app-tutorial-part7.png) + +To get the buttons to work nicely we need to create an image border add 2 new UIID’s named `LoginButtonGoogle` & +`LoginButtonFacebook`. Both should be identical with the exception of the color for the background…​ + + * In the color tab set the foreground to `ffffff` and transparency to 0 (naturally uncheck derive in both cases). + + * In the `Alignment` tab uncheck derive and define the alignment as `Center`. + + * In the padding and margin tabs define all top/bottom/left/right paddings/margins to be 1 millimeter. + + * In the font tab define the system font to be large. + + * In the border section click the `Image Border Wizard` button. For the Facebook button enter 3B5999 to all the color fields +for the Google button enter DD4B39 to all the color fields. Increase the arc width/height to 15 and then move to the +`Cut Image` section. Enter 14 for the top/bottom/left & right values and press OK. This will effectively cut 9 multi images +out of the given image and make a border out of them! + +![Image Border Start](/blog/building-a-chat-app-with-codename-one-part-1/chat-app-tutorial-part8.png) + +![Image Border Cutting](/blog/building-a-chat-app-with-codename-one-part-1/chat-app-tutorial-part9.png) + +### Integrating These Changes + +Now we can easily integrate the above changes in the code by just changing these lines: + + + Button loginWithGoogle = new Button("Signin with Google"); + loginWithGoogle.setUIID("LoginButtonGoogle"); + Button loginWithFacebook = new Button("Signin with Facebook"); + loginWithFacebook.setUIID("LoginButtonFacebook"); + Style iconFontStyle = UIManager.getInstance().getComponentStyle("IconFont"); + loginWithFacebook.setIcon(FontImage.create(" ue96c ", iconFontStyle)); + loginWithGoogle.setIcon(FontImage.create(" ue976 ", iconFontStyle)); + +These effectively assign the new UIID and create two icons with the given font defined within the icon font style! + +### Other Posts In This Series + +This is a multi-part series of posts including the following parts: + + * [Part 1 – Initial UI](/blog/building-a-chat-app-with-codename-one-part-1.html) + + * [Part 2 – Login With Google](/blog/building-a-chat-app-with-codename-one-part-2.html) + + * [Part 3 – Login With Facebook](/blog/building-a-chat-app-with-codename-one-part-3.html) + + * [Part 4 – The Contacts Form](/blog/building-a-chat-app-with-codename-one-part-4.html) + + * [Part 5 – The Chat Form](/blog/building-a-chat-app-with-codename-one-part-5.html) + + * [Part 6 – Native Push & Finishing Up](/blog/building-a-chat-app-with-codename-one-part-6.html) + +You can check out the final source code of this tutorial [here](https://github.com/codenameone/codenameone-demos/tree/master/SocialChat). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Nigel Chomba** — July 20, 2015 at 8:39 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html#comment-24171)) + +> Lets move on Shai…..whats next? + + +### **Shai Almog** — July 20, 2015 at 2:43 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html#comment-21651)) + +> We will post it when its ready. + + +### **Nigel Chomba** — July 22, 2015 at 5:22 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html#comment-22252)) + +> Great sir + + +### **Michael du Plessis** — April 10, 2017 at 1:36 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html#comment-23332)) + +> I notice in the documentation that you recommend not using .getTitleArea().setUIID(“Container”); anymore because it allowed hacks. +> How can we remove the TitleArea now? + + +### **Shai Almog** — April 11, 2017 at 4:36 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html#comment-23354)) + +> getTitleArea() is deprecated because it was used as getTitleArea().removeAll(); getTitleArea().addComponent(myCmp); +> +> That was a hack we allowed in some cases but now that we have the toolbar it’s redundant & messy. Even when we allowed the hack it was discouraged because it relies too much on implementation details. However, setting the UIID doesn’t rely as much on the implementation details. +> +> You can avoid this though by adding a UIID TitleArea and overriding the styling to make it transparent, without a border, padding or margin. + + +### **Michael du Plessis** — April 18, 2017 at 8:34 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html#comment-23438)) + +> Ah I understand! Thank you for the explanation. I will also play around with the customisation of TitleArea within the Theme Editor. + + +### **Francesco Galgani** — November 28, 2017 at 8:58 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html#comment-23834)) + +> About “FontImage.create(” ue96c “, iconFontStyle)”, what is the meaning of ” ue96c “? How is chosen or generated this string? Thank you. + + +### **Shai Almog** — November 29, 2017 at 6:50 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html#comment-23771)) + +> This tutorial was written before we had material design icons integrated into Codename One so I used the fontello fonts which include various icons. When you download a font from fontello you get an HTML with all the codes in the font. I explained this here: [https://www.codenameone.com…]() + + +### **Francesco Galgani** — December 1, 2017 at 6:21 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html#comment-23903)) + +> Francesco Galgani says: +> +> I’ve just seen that interesting tutorial, useful if I need custom icons not included in the material icons set. Thank you + + +### **Ahnaf Tahmeed** — May 3, 2020 at 11:20 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html#comment-21399)) + +> [Ahnaf Tahmeed](https://lh3.googleusercontent.com/a-/AOh14GhIoPjnxowmY7XUvnUL5kz7LSzCdIa-9HB-kCXxPg) says: +> +> Do I need to be a JAVA expert to go through this course …?? + + +### **Shai Almog** — May 4, 2020 at 6:03 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-1.html#comment-21398)) + +> Shai Almog says: +> +> No. But you should know Java language syntax. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/building-a-chat-app-with-codename-one-part-2.md b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-2.md new file mode 100644 index 0000000000..82ce07517b --- /dev/null +++ b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-2.md @@ -0,0 +1,351 @@ +--- +title: Building A Chat App With Codename One Part 2 +slug: building-a-chat-app-with-codename-one-part-2 +url: /blog/building-a-chat-app-with-codename-one-part-2/ +original_url: https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-2.html +aliases: +- /blog/building-a-chat-app-with-codename-one-part-2.html +date: '2015-07-21' +author: Shai Almog +--- + +![Header Image](/blog/building-a-chat-app-with-codename-one-part-2/google-sign-in.png) + +In the second part of this tutorial we will cover the login process for Google and getting a unique id. We’ll try to +write generic code that we can later reuse for the Facebook login process. But first lets cover what “signing in” +actually means…​ + +When you handle your own user list and a user signs in thru registration, you can generally ask that user anything. +However, when the user signs in thru Facebook, Google or any other service then you are at the mercy of that +service for user details…​ This is painfully clear with such services that don’t provide even an email address by +default when logging in. It is sometimes accessible in Facebook but only for users who didn’t choose to hide it. + +Worse, one of the main reasons for using such a service is to access the contacts…​ However, Facebook no longer +allows developers access to your Facebook friends. A Facebook app developer can only access the list of friends +who have the app installed and to accomplish that we will need to “invite” people to use/install the app. + +### Getting Started – Configuration + +Pretty much everything discussed in this blog post is covered [here](http://www.codenameone.com/google-login.html). +However, that is a rather general post so in this tutorial I’ll try to be more specific. + +Start by going to the the Google developer console: + +Create a new app by pressing the create button: + +![Create New Project](/blog/building-a-chat-app-with-codename-one-part-2/chat-app-tutorial-google-login-1.png) + +Just enter the name of the app e.g. for this case its SocialChat and press “Create”: + +![Create New Project](/blog/building-a-chat-app-with-codename-one-part-2/chat-app-tutorial-google-login-2.png) + +Now can select the API’s section where you should see the new project page: + +![New Project Page](/blog/building-a-chat-app-with-codename-one-part-2/chat-app-tutorial-google-login-3.png) + +In that project you should click the Google+ API in the “Social” section: + +![Google+ API Section](/blog/building-a-chat-app-with-codename-one-part-2/chat-app-tutorial-google-login-4.png) + +In the credentials section create a new client id, first we need to create one for a web application. This will be used by the simulator +so we can debug the application on the desktop. It will also be used by ports for JavaScript, Desktop and effectively +everything other than iOS & Android: + +![Google+ API Section](/blog/building-a-chat-app-with-codename-one-part-2/chat-app-tutorial-google-login-5.png) + +The consent screen is used to prompt users for permissions, you should normally fill it up properly for a “real world” application +but in this case we left it mostly empty for simplicities sake: + +![Consent screen](/blog/building-a-chat-app-with-codename-one-part-2/chat-app-tutorial-google-login-6.png) + +We now need to add Android/iOS native app bindings in much the same way as we did the web app + +![Web App](/blog/building-a-chat-app-with-codename-one-part-2/chat-app-tutorial-google-login-7.png) + +To build a native Android app make sure you setup the keystore correctly for your application. If you don’t have +an Android certificate you can use our visual wizard or use the command line mentioned in our [signing tutorial](/signing.html). + +Now that you have a certificate you need two values for your app, the first is the package name which must match +the package name of your main class (the one with the start, stop methods). It should be listed in the Codename One properties +section. Make sure to use a name that is 100% unique to you and using your own domain, don’t use the com.codename1 prefix or +anything such as that…​ + +You also need the SHA1 value for your certificate, this is explained by Google here: + +Effectively you need to run this command line: + + + $ keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v + +This will prompt for a password then print several lines of data one of which should start with `SHA1` that is the value +that you will need for the Android app. + +![Android App](/blog/building-a-chat-app-with-codename-one-part-2/chat-app-tutorial-google-login-8.png) + +The iOS app needs the same package name as the bundle id. It also needs the appstore id which you can get from +itunes, it should appear as the prefix for your apps provisioning profile. If your app is correctly configured e.g. +by using the Codename One certificate wizard, then you should see it in the project properties under the Codename One→iOS section. + +![iOS App](/blog/building-a-chat-app-with-codename-one-part-2/chat-app-tutorial-google-login-9.png) + +After everything is completed you should see something similar to this: + +![End Result](/blog/building-a-chat-app-with-codename-one-part-2/chat-app-tutorial-google-login-10.png) + +### Project Configuration + +We now need to set some important build hints in the project so it will work correctly. To set the build hints just right click the project +select project properties and in the Codename One section pick the second tab. Add these entries into the table: + + + ios.gplus.clientId=your ios client ID + +![Build Hints](/blog/building-a-chat-app-with-codename-one-part-2/chat-app-tutorial-google-login-11.png) + +### The Code + +So now that all of that is in place we would want it to work with our app…​ + +First to make the code more generic we’ll define this interface that we can implement both for Facebook & Google +thus generalizing the login code: + + + static interface UserData { + public String getName(); + public String getId(); + public String getImage(); + public void fetchData(String token, Runnable callback); + } + +The way this interface is meant to work, is that we would invoke fetchData after the login process completes to fetch +the data from Google/Facebook and then have name/id & image available to us. + +Also notice that the fetchData is asynchronous and will invoke a callback when it completes. We could have made +it synchronous and used `invokeAndBlock`. + +The code that binds this to the button looks like this: + + + loginWithGoogle.addActionListener((e) -> { + tokenPrefix = "google"; + Login gc = GoogleConnect.getInstance(); + gc.setClientId("1013232201263-lf4aib14r7g6mln58v1e36ibhktd79db.apps.googleusercontent.com"); + gc.setRedirectURI("https://www.codenameone.com/oauth2callback"); + gc.setClientSecret("-------------------"); + doLogin(gc, new GoogleData(), false); + }); + +Notice that we hid the client secrete and used the `GoogleData` class which is effectively the implementation of the +`UserData` interface. The `GoogleData` class looks like this: + + + class GoogleData extends ConnectionRequest implements UserData { + private Runnable callback; + private Map parsedData; + + @Override + public String getName() { + return (String) parsedData.get("displayName"); + } + + @Override + public String getId() { + return parsedData.get("id").toString(); + } + + @Override + public String getImage() { + Map imageMeta = ((Map) parsedData.get("image")); + return (String)imageMeta.get("url"); + } + + @Override + public void fetchData(String token, Runnable callback) { + this.callback = callback; + addRequestHeader("Authorization", "Bearer " + token); + setUrl("https://www.googleapis.com/plus/v1/people/me"); + setPost(false); + NetworkManager.getInstance().addToQueue(this); + } + + @Override + protected void handleErrorResponseCode(int code, String message) { + //access token not valid anymore + if(code >= 400 && code <= 410){ + doLogin(GoogleConnect.getInstance(), this, true); + return; + } + super.handleErrorResponseCode(code, message); + } + + @Override + protected void readResponse(InputStream input) throws IOException { + JSONParser parser = new JSONParser(); + parsedData = parser.parseJSON(new InputStreamReader(input, "UTF-8")); + } + + @Override + protected void postResponse() { + callback.run(); + } + } + +Generally there isn’t all that much to the class. `fetchData` uses a connection request to connect to a URL in the +Google+ API that returns details about the user when the token is set. These details are returned as a JSON string +that we then parse and set to the right variables. + +The `JSONParser` class returns the JSON data as a tree of lists & maps that we can traverse thru to extract the data we need. + +One value that might not be clear to the casual observer is the `token`, this is a string that contains a “key” to the users +account. Facebook/Google etc. keep the passwords for their users hashed in their database (effectively meaning +even they don’t know the passwords), so to prove that we got permission from the user to access their data we +get a unique token that looks like a long string of gibberish and we can use that when accessing their respective API’s +thus validating ourselves. This is a very common practice…​ However, tokens expire occasionally and thus you might +need to “refresh” your token by logging in again as demonstrated in the next block of code. + +Now we can go to the actual login process which is generic for both Google & Facebook login thanks to the class above +and the builtin abstractions in Codename One: + + + private String fullName; + private String uniqueId; + private String imageURL; + void doLogin(Login lg, UserData data, boolean forceLogin) { + if(!forceLogin) { + if(lg.isUserLoggedIn()) { + showContactsForm(data); + return; + } + + // if the user already logged in previously and we have a token + String t = Preferences.get(tokenPrefix + "token", (String)null); + if(t != null) { + // we check the expiration of the token which we previously stored as System time + long tokenExpires = Preferences.get(tokenPrefix + "tokenExpires", (long)-1); + if(tokenExpires < 0 || tokenExpires > System.currentTimeMillis()) { + // we are still logged in + showContactsForm(data); + return; + } + } + } + + lg.setCallback(new LoginCallback() { + @Override + public void loginFailed(String errorMessage) { + Dialog.show("Error Logging In", "There was an error logging in: " + errorMessage, "OK", null); + } + + @Override + public void loginSuccessful() { + // when login is successful we fetch the full data + data.fetchData(lg.getAccessToken().getToken(), ()-> { + // we store the values of result into local variables + uniqueId = data.getId(); + fullName = data.getName(); + imageURL = data.getImage(); + + // we then store the data into local cached storage so they will be around when we run the app next time + Preferences.set("fullName", fullName); + Preferences.set("uniqueId", uniqueId); + Preferences.set("imageURL", imageURL); + Preferences.set(tokenPrefix + "token", lg.getAccessToken().getToken()); + + // token expiration is in seconds from the current time, we convert it to a System.currentTimeMillis value so we can + // reference it in the future to check expiration + Preferences.set(tokenPrefix + "tokenExpires", tokenExpirationInMillis(lg.getAccessToken())); + showContactsForm(data); + }); + } + }); + lg.doLogin(); + } + +Now that’s a big block of code but it doesn’t really do that much. All it does is delegate to the `UserData` interface +and validates the token. It also stores returned data and shows the next form (which we won’t cover right now). + +The last piece of code for this section is a small utility method that we used for token expiration detection: + + + /** + * token expiration is in seconds from the current time, we convert it to a System.currentTimeMillis value so we can + * reference it in the future to check expiration + */ + long tokenExpirationInMillis(AccessToken token) { + String expires = token.getExpires(); + if(expires != null && expires.length() > 0) { + try { + // when it will expire in seconds + long l = (long)(Float.parseFloat(expires) * 1000); + return System.currentTimeMillis() + l; + } catch(NumberFormatException err) { + // ignore invalid input + } + } + return -1; + } + +This effectively allows us to detect if the token expired or not in a future execution of the app. + +Note: I’ve added the tokenPrefix variable which was missing in the original post, it allows differentiating between +a Google and Facebook login and the fact that it was missing caused some amusing bugs. + +__ | The original post discussed using the email address as the unique user ID which was the initial direction +we were going for. But we since decided to go in a different route with user ID’s (similar to the Facebook experience). +We also made some minor changes to error handling logic making the code more robust. We also changed the token expiration parsing logic to use a float value. +---|--- + +__ | Updated again to remove the gplay-service build hint which is no longer needed +---|--- + +### Other Posts In This Series + +This is a multi-part series of posts including the following parts: + + * [Part 1 – Initial UI](/blog/building-a-chat-app-with-codename-one-part-1.html) + + * [Part 2 – Login With Google](/blog/building-a-chat-app-with-codename-one-part-2.html) + + * [Part 3 – Login With Facebook](/blog/building-a-chat-app-with-codename-one-part-3.html) + + * [Part 4 – The Contacts Form](/blog/building-a-chat-app-with-codename-one-part-4.html) + + * [Part 5 – The Chat Form](/blog/building-a-chat-app-with-codename-one-part-5.html) + + * [Part 6 – Native Push & Finishing Up](/blog/building-a-chat-app-with-codename-one-part-6.html) + +You can check out the final source code of this tutorial [here](https://github.com/codenameone/codenameone-demos/tree/master/SocialChat). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Nigel Chomba** — July 22, 2015 at 5:24 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-2.html#comment-22264)) + +> i am following…..Great stuff co-founder +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-2.html) + + +### **Francesco Galgani** — February 4, 2018 at 2:32 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-2.html#comment-23913)) + +> Are the information and code of this tutorial about Facebook login and Google login still valid? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-2.html) + + +### **Shai Almog** — February 5, 2018 at 5:05 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-2.html#comment-23617)) + +> Should be. It’s a bit old so I’d like to refresh it eventually. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-2.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/building-a-chat-app-with-codename-one-part-3.md b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-3.md new file mode 100644 index 0000000000..97a8870e10 --- /dev/null +++ b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-3.md @@ -0,0 +1,189 @@ +--- +title: Building A Chat App With Codename One Part 3 +slug: building-a-chat-app-with-codename-one-part-3 +url: /blog/building-a-chat-app-with-codename-one-part-3/ +original_url: https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-3.html +aliases: +- /blog/building-a-chat-app-with-codename-one-part-3.html +date: '2015-07-28' +author: Shai Almog +--- + +![Header Image](/blog/building-a-chat-app-with-codename-one-part-3/facebook-login-blue.png) + +In the previous section we went over the login with Google process, in this section we’ll go over the login with Facebook. +At this time we’ll skip the “invite friends” option since that is blog post all on its own and we can just add that functionality +to the completed application. + +Facebook has a “get friends” API call that we can use, the downside of that is that it will only return our +friends that have already joined the app so we won’t be able to contact anyone on an arbitrary basis. + +### Getting Started – Configuration + +Getting started with Facebook is pretty similar to the Google process and you can learn about it [here](http://www.codenameone.com/facebook-login.html). + +You need to go to and signup to create an application: + +![Create New App](/blog/building-a-chat-app-with-codename-one-part-3/chat-app-tutorial-facebook-login-1.png) + +You need to repeat the process for web, Android & iOS (web is used by the simulator): + +![Pick Platform](/blog/building-a-chat-app-with-codename-one-part-3/chat-app-tutorial-facebook-login-2.png) + +For the first platform you need to enter the app name: + +![Pick Name](/blog/building-a-chat-app-with-codename-one-part-3/chat-app-tutorial-facebook-login-3.png) + +And provide some basic details: + +![Details](/blog/building-a-chat-app-with-codename-one-part-3/chat-app-tutorial-facebook-login-4.png) + +For iOS we need the bundle ID which is the exact same thing we used in the Google+ login to identify the iOS app +its effectively your package name: + +![Details](/blog/building-a-chat-app-with-codename-one-part-3/chat-app-tutorial-facebook-login-5.png) + +You should end up with something that looks like this: + +![Details](/blog/building-a-chat-app-with-codename-one-part-3/chat-app-tutorial-facebook-login-6.png) + +The Android process is pretty similar but in this case we need the activity name too. + +Important: notice there is a mistake in the screenshot, the activity name should match the main class name followed +by the word Stub (uppercase s). In this case it should be SocialChatStub. + +![Details](/blog/building-a-chat-app-with-codename-one-part-3/chat-app-tutorial-facebook-login-7.png) + +Just like on Google+ we need to generate a hash to verify that the app is indeed ours to Facebook and we do this +using the same keytool approach using the command line: + + + keytool -exportcert -alias (your_keystore_alias) -keystore (path_to_your_keystore) | openssl sha1 -binary | openssl base64 + +![Hash](/blog/building-a-chat-app-with-codename-one-part-3/chat-app-tutorial-facebook-login-8.png) + +Lastly you need to publish the Facebook app by flipping the switch in the apps “Status & Review” page as such: + +![Enable The App](/blog/building-a-chat-app-with-codename-one-part-3/chat-app-tutorial-facebook-login-9.png) + +### Project Configuration + +We now need to set some important build hints in the project so it will work correctly. To set the build hints just right click the project +select project properties and in the Codename One section pick the second tab. Add these entries into the table: + + + facebook.appId=... + +The app ID will be visible in your Facebook app page in the top left position. + +### The Code + +So now that all of that is in place we would want it to work with our app…​ + +Add the event handling for logging in with Facebook as such: + + + loginWithFacebook.addActionListener((e) -> { + tokenPrefix = "facebook"; + Login fb = FacebookConnect.getInstance(); + fb.setClientId("739727009469185"); + fb.setRedirectURI("http://www.codenameone.com/"); + fb.setClientSecret("-------"); + doLogin(fb, new FacebookData(), false); + }); + +Notice that the client ID, redirect, secret etc. are all relevant to the simulator login and won’t be used on Android/iOS +where native Facebook login will kick into place. + +Similarly to the Google+ implementation we’ll create a class to abstract the Facebook connection based on the interface +we defined the last time around: + + + class FacebookData implements UserData { + String name; + String id; + + @Override + public String getName() { + return name; + } + + @Override + public String getId() { + return id; + } + + @Override + public String getImage() { + return "http://graph.facebook.com/v2.4/" + id + "/picture"; + } + + @Override + public void fetchData(String token, Runnable callback) { + ConnectionRequest req = new ConnectionRequest() { + @Override + protected void readResponse(InputStream input) throws IOException { + JSONParser parser = new JSONParser(); + Map parsed = parser.parseJSON(new InputStreamReader(input, "UTF-8")); + name = (String) parsed.get("name"); + id = (String) parsed.get("id"); + } + + @Override + protected void postResponse() { + callback.run(); + } + + @Override + protected void handleErrorResponseCode(int code, String message) { + //access token not valid anymore + if(code >= 400 && code <= 410){ + doLogin(FacebookConnect.getInstance(), FacebookData.this, true); + return; + } + super.handleErrorResponseCode(code, message); + } + }; + req.setPost(false); + req.setUrl("https://graph.facebook.com/v2.4/me"); + req.addArgumentNoEncoding("access_token", token); + NetworkManager.getInstance().addToQueue(req); + } + } + +This is really trivial code, we just connect to Facebooks Graph API and provide the token. From here on its +just a matter of parsing the returned data which contains only two keys for the user name and the unique id +which we can use later on when setting up a chat. + +That’s it for Facebook login, next time we’ll get into accessing the contacts and showing the contacts form UI. + +__ | the original post discussed using the email address as the unique user ID which was the initial direction +we were going for. But we since decided to go in a different route with user ID’s (similar to the Facebook experience). +We also made some minor changes to error handling logic making the code more robust. +---|--- + +### Other Posts In This Series + +This is a multi-part series of posts including the following parts: + + * [Part 1 – Initial UI](/blog/building-a-chat-app-with-codename-one-part-1.html) + + * [Part 2 – Login With Google](/blog/building-a-chat-app-with-codename-one-part-2.html) + + * [Part 3 – Login With Facebook](/blog/building-a-chat-app-with-codename-one-part-3.html) + + * [Part 4 – The Contacts Form](/blog/building-a-chat-app-with-codename-one-part-4.html) + + * [Part 5 – The Chat Form](/blog/building-a-chat-app-with-codename-one-part-5.html) + + * [Part 6 – Native Push & Finishing Up](/blog/building-a-chat-app-with-codename-one-part-6.html) + +You can check out the final source code of this tutorial [here](https://github.com/codenameone/codenameone-demos/tree/master/SocialChat). + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/building-a-chat-app-with-codename-one-part-4.md b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-4.md new file mode 100644 index 0000000000..67f5234d2a --- /dev/null +++ b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-4.md @@ -0,0 +1,758 @@ +--- +title: Building A Chat App With Codename One Part 4 +slug: building-a-chat-app-with-codename-one-part-4 +url: /blog/building-a-chat-app-with-codename-one-part-4/ +original_url: https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-4.html +aliases: +- /blog/building-a-chat-app-with-codename-one-part-4.html +date: '2015-08-04' +author: Shai Almog +--- + +![Header Image](/blog/building-a-chat-app-with-codename-one-part-4/building-a-chat-app-tutorial-part-4.png) + +This tutorial is starting to get interesting…​. In this section we’ll go deep into animations, special effects, search +styling and extracting contacts. In the previous sections we built the first form of the app, logged in and now we +need to show the actual login form. Even more importantly we need to show it with style like this: + +![Login UX](/blog/building-a-chat-app-with-codename-one-part-4/chat-app-tutorial-contacts-form-1.gif) + +(notice that you should see an animated gif above naturally we reduced quality to make it smaller but it still takes +a moment to load). + +What we see here is how the login form animates out by sliding out the buttons to the right then morphing the background +into the title area of the following form. We’ll get into how this is done soon enough…​ But first lets get the contact details! + +### New Contacts API + +First we need to add contact access permissions to the Google API by adding the line +‘gc.setScope(“profile email [https://www.googleapis.com/auth/plus.me”);’](https://www.googleapis.com/auth/plus.me) +into the initial login as such: + + + loginWithGoogle.addActionListener((e) -> { + tokenPrefix = "google"; + Login gc = GoogleConnect.getInstance(); + gc.setScope("profile email https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.me"); + gc.setClientId("1013232201263-lf4aib14r7g6mln58v1e36ibhktd79db.apps.googleusercontent.com"); + gc.setRedirectURI("https://www.codenameone.com/oauth2callback"); + gc.setClientSecret("uvu03IXOhx9sO8iPcmDfuX3R"); + doLogin(gc, new GoogleData()); + }); + +We are effectively asking for more permissions. Notice that profile and email are shorthand syntax for the full URI +accepted by Google and the values in the scope are separated by a space. + +To make contacts access generic we changed a few things in the interfaces defined in the previous steps: + + + static class ContactData { + public String uniqueId; + public String name; + public String imageUrl; + } + +First we added the simple contact data abstract class to represent a specific contact. Normally, we would just use +something simpler but since Google & Facebook have radically different image sources we had to create two +different implementations of this class. + + + static interface UserData { + public String getName(); + public String getId(); + public String getImage(); + public void fetchData(String token, Runnable callback); + public ContactData[] getContacts(); + } + +We only added one method to user data, the `getContacts` method. For simplicity we fetch all the contacts and do +so synchronously. In a future iteration we might improve this by creating an implementation that “streams” the contacts +but for now we wanted something simple that will also lend itself well to search. + +### Getting The Contacts On Google + +We connect to the Google webservice and get all visible contacts. Here we don’t have to limit ourselves to people +who installed the app and this gives us more information: + + + private String token; + + @Override + public ContactData[] getContacts() { + ArrayList dat = new ArrayList<>(); + ConnectionRequest req = new ConnectionRequest() { + @Override + protected void readResponse(InputStream input) throws IOException { + JSONParser parser = new JSONParser(); + Map parsed = parser.parseJSON(new InputStreamReader(input, "UTF-8")); + java.util.List data = (java.util.List)parsed.get("items"); + for(Object current : data) { + Map cMap = (Map)current; + String name = (String)cMap.get("displayName"); + if(name == null) { + continue; + } + String type =(String)cMap.get("objectType"); + if(!type.equals("person")) { + continue; + } + String id = cMap.get("id").toString(); + ContactData cd = new ContactData(); + cd.name = name; + cd.uniqueId = id; + + if(cMap.containsKey("image")) { + cd.imageUrl = (String)((Map)cMap.get("image")).get("url");; + } + + dat.add(cd); + } + } + }; + req.setPost(false); + req.setUrl("https://www.googleapis.com/plus/v1/people/me/people/visible"); + if(token == null) { + token = Preferences.get("googletoken", (String)null); + } + req.addArgumentNoEncoding("key", token); + NetworkManager.getInstance().addToQueueAndWait(req); + + ContactData[] cd = new ContactData[dat.size()]; + dat.toArray(cd); + return cd; + } + +The code is a bit large but is in fact really simple, we get the Google token which we provide to the +Google API to request the contacts list. We then do a synchronous call using `addToQueueAndWait` which is +really convenient in this case and add all the entries into an array list. + +Notice that we skip object types that aren’t “person”, in the Google+ API the pages you follow are also returned so +its necessary to remove some redundant noise. + +The JSON returned keeps all the contacts who are connected under the data property so we parse the JSON and +get the array of friends from the `items` property. Then its just a matter of going over the contacts and constructing +a new contact object. + +### Getting The Contacts From Facebook + +Facebook is pretty similiar, we need to query the Graph API for the users and iterate them. The current code only +gets the first page of users hence its a bit flawed but it should be easily adaptable for paging thru the full result list. +Notice that Facebook will only return the users that signed in to the app so while the result might list your hundreds of +friends you might still get a blank list if none of them signed into the app. + + + @Override + public ContactData[] getContacts() { + ArrayList dat = new ArrayList<>(); + ConnectionRequest req = new ConnectionRequest() { + @Override + protected void readResponse(InputStream input) throws IOException { + JSONParser parser = new JSONParser(); + Map parsed = parser.parseJSON(new InputStreamReader(input, "UTF-8")); + //name = (String) parsed.get("name"); + java.util.List data = (java.util.List)parsed.get("data"); + for(Object current : data) { + Map cMap = (Map)current; + String name = (String)cMap.get("name"); + if(name == null) { + continue; + } + String id = cMap.get("id").toString(); + ContactData cd = new ContactData(); + cd.name = name; + cd.uniqueId = id; + cd.imageUrl = "http://graph.facebook.com/v2.4/" + id + "/picture"; + dat.add(cd); + } + } + }; + req.setPost(false); + req.setUrl("https://graph.facebook.com/v2.4/me/friends"); + if(token == null) { + token = Preferences.get("facebooktoken", (String)null); + } + req.addArgumentNoEncoding("access_token", token); + NetworkManager.getInstance().addToQueueAndWait(req); + + ContactData[] cd = new ContactData[dat.size()]; + dat.toArray(cd); + return cd; + } + +This is almost identical to the Google version, the only differences are in the structure of the JSON returned and the URL’s. + +### Adding The Things We Need To The Theme + +For the next section to work we need to add several multi-images to the theme using `Quick Add Multi Image` in the image +menu in the designer then picking “Very High” as the source image resolution. This will automatically adapt the image +to all DPI’s. + +First we need [rounded-mask.png](/files/rounded-mask.png): + +![rounded-mask.png](/blog/building-a-chat-app-with-codename-one-part-4/rounded-mask.png) + +This image will be used to convert square pictures into round images as my picture in the title area that you can see above. +Effectively masking uses the black pixels to remove the corresponding pixels in the image while leaving the white pixels, +gray pixels will remain translucent. + +Then we need [rounded-border.png](/files/rounded-border.png): + +![rounded-border.png](/blog/building-a-chat-app-with-codename-one-part-4/rounded-border.png) + +We will place this image underneath the mask image thus resulting in a border/shadow effect. This is important for +appearance since the source image is downloaded from Facebook/Google etc. and might have a color clash with the +toolbar. That way we guarantee that the border will fit in with the toolbar. + +Lastly we add the image that will be placed in the toolbar area [social-chat-tutorial-image-top.jpg](/files/social-chat-tutorial-image-top.jpg): + +![social-chat-tutorial-image-top.jpg](/blog/building-a-chat-app-with-codename-one-part-4/social-chat-tutorial-image-top.jpg) + +Now that all the images are in place we need to add some UIID’s into the theme to support the additional components +we will use, first we start with the `LargeIconFont` UIID which is very similar to the `IconFont` UIID we introduced the +last time around, but it doesn’t override the foreground color and is sized at 4mm. This icon font is used in the body +of the application so we want it to use the default colors so it will integrate properly, otherwise the white foreground +of the standard icon font might vanish. + +![Large Icon Font UIID Definition](/blog/building-a-chat-app-with-codename-one-part-4/chat-app-tutorial-contacts-form-2.png) + +![Large Icon Font UIID Definition](/blog/building-a-chat-app-with-codename-one-part-4/chat-app-tutorial-contacts-form-3.png) + +We’ll also add the rounded-border image as a UIID that we can apply to the actual image later by adding a `UserImage` +UIID and setting the background image to `rounded-border.png` and the background behavior to scaled to fit. We +also need to set the transparency to 0 to make sure that the style is transparent. + +![UserImage UIID Definition](/blog/building-a-chat-app-with-codename-one-part-4/chat-app-tutorial-contacts-form-4.png) + +![UserImage UIID Definition](/blog/building-a-chat-app-with-codename-one-part-4/chat-app-tutorial-contacts-form-5.png) + +We also want to make the `TitleArea` more controllable thru opacity. Currently its defined as an +image border which is problematic so we will change the border to be “Empty”, define the background color to +`5bc8fb` and set the transparency to 255 which will give the same effect but allow us more control in the code. + +![TitleArea UIID Definition](/blog/building-a-chat-app-with-codename-one-part-4/chat-app-tutorial-contacts-form-6.png) + +![TitleArea UIID Definition](/blog/building-a-chat-app-with-codename-one-part-4/chat-app-tutorial-contacts-form-7.png) + +And finally `MultiButton’s don’t have a clickable state in the default theme so we need to update their selected state +to have 255 transparency (opaque) and have the background color `5bc8fb` which will provide us with a click effect. + +![MultiButton UIID Definition](/blog/building-a-chat-app-with-codename-one-part-4/chat-app-tutorial-contacts-form-8.png) + +### Showing The Contacts + +To show the contacts we will need several new UI elements and several new class variables so first lets define the new +class members that are needed for this: + + + private String fullName; + private String uniqueId; + private String imageURL; + private static EncodedImage userPlaceholder; + private EncodedImage roundPlaceholder; + private Image mask; + private ContactData[] contacts; + +These members are defined in the main class and include images that we will use to show the individual entries and +create a “rounding” mask to make the rounded picture effect on the title bar area. We also added a variable containing +the contacts array that we can use later in the code. + +To initialize these variables we’ll use the `init(Object context)` method, of the main class right after the theme initialization. +This code happens only once per app execution and is a great place to load/initialize things. Notice that it should +still be a relatively fast method so don’t do heavy processing there otherwise app launch might be slowed down and the +OS might kill your unresponsive app. + + + Style iconFontStyle = UIManager.getInstance().getComponentStyle("LargeIconFont"); + iconFontStyle.setBgTransparency(255); + FontImage fnt = FontImage.create(" ue80f ", iconFontStyle); + userPlaceholder = fnt.toEncodedImage(); + mask = theme.getImage("rounded-mask.png"); + roundPlaceholder = EncodedImage.createFromImage(userPlaceholder.scaled(mask.getWidth(), mask.getHeight()).applyMask(mask.createMask()), false); + fullName = Preferences.get("fullName", null); + uniqueId = Preferences.get("uniqueId", null); + imageURL = Preferences.get("imageURL", null); + +We are doing several interesting things here, we are defining the icon style to use the `LargeIconFont` UIID which +allows us to create a scalable placeholder image. This is then used for two purposes in the code, placeholder for +pictures of our contacts (before the image is downloaded by `URLImage`) and for “my picture” (currently logged in user) +in the title area. In the “my picture” case it will be rounded using the rounded-mask image mentioned above. + +This line is pretty complex so lets break it down a bit: + + + roundPlaceholder = EncodedImage.createFromImage(userPlaceholder.scaled(mask.getWidth(), mask.getHeight()).applyMask(mask.createMask()), false); + +What we do here is several different things, `userPlaceholder.scaled(mask.getWidth(), mask.getHeight())` takes the +`userPlaceholder` and makes sure it matches the size of the mask perfectly. If it doesn’t we’ll get an exception. +We then take the mask image `mask.createMask()` and convert it to an internal representation. You might +recall from above that the mask image is this: + +![rounded-mask.png](/blog/building-a-chat-app-with-codename-one-part-4/rounded-mask.png) + +So the `createMask` method extracts these pixels and converts them to an internal representation that we can +later apply to an arbitrary image. This is a slightly expensive operation so we don’t recommend doing it often. +We then take the scaled image and apply the newly created mask onto the scaled image which generates +a round image with the call to `applyMask`. + +However, we need an instance of EncodedImage and not just a regular image so we use `EncodedImage.createFromImage` +with the false argument (indicating the image isn’t opaque) to convert the resulting placeholder to an encoded image. +Notice that if the image is already an encoded image this method does nothing…​ + +We need an encoded image since later in the code we will use `URLImage` which expects `EncodedImage`, the +`EncodedImage` is generally a more efficient way of storing images in terms of RAM and it allows us to get the image +data more effectively. It means the image PNG/JPEG data is still available…​ All standard/multi images returned form the resource +file are `EncodedImage’s which helps with memory utilization. + +Now that everything is in place we can start with the main method that shows the UI: + + + void showContactsForm(UserData data) { + Form contactsForm = new Form("Contacts"); + contactsForm.setLayout(new BoxLayout(BoxLayout.Y_AXIS)); + + // the toolbar is created into a layer on the content pane. This allows us to render behind it and leave it semi transparent + Toolbar tb = new Toolbar(true); + + // we want the title area to be transparent so it won't get in the way + contactsForm.getTitleArea().setUIID("Container"); + + // folds the toolbar automatically as we scroll down, shows it if we scroll back up + tb.setScrollOffUponContentPane(true); + contactsForm.setToolBar(tb); + + // we want the image behind the toolbar to stretch and fit the entire screen and leave no margin + Label titleLabel = new Label(" "); + Style titleLabelStyle = titleLabel.getUnselectedStyle(); + titleLabelStyle.setBgImage(theme.getImage("social-chat-tutorial-image-top.jpg")); + titleLabelStyle.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL); + titleLabelStyle.setPadding(tb.getPreferredH(), tb.getPreferredH(), tb.getPreferredH(), tb.getPreferredH()); + titleLabelStyle.setPaddingUnit(Style.UNIT_TYPE_PIXELS, Style.UNIT_TYPE_PIXELS, Style.UNIT_TYPE_PIXELS, Style.UNIT_TYPE_PIXELS); + titleLabelStyle.setMargin(0, 0, 0, 0); + + contactsForm.addComponent(titleLabel); + + // the behavior of the title is rather complex so we extract it to a separate method + tb.setTitleComponent(createTitleComponent(contactsForm)); + + InfiniteProgress ip = new InfiniteProgress(); + contactsForm.addComponent(ip); + + loadContacts(data, ip, contactsForm.getContentPane()); + + // creates the morph and other animations from the main form to the second form of the app + createMorphEffect(titleLabel); + + contactsForm.show(); + } + +This is a relatively big method but it delegates most of the hard work to other methods so most of the stuff done +here isn’t very complex or even interesting. Here: + + + contacts.getTitleArea().setUIID("Container"); + +We just make the title area transparent (since the Container UIID is always transparent), this allows us to style +the toolbar in a rather elaborate way in the `createTitleComponent` method. + +This code: + + + Label titleLabel = new Label(" "); + Style titleLabelStyle = titleLabel.getUnselectedStyle(); + titleLabelStyle.setBgImage(theme.getImage("social-chat-tutorial-image-top.jpg")); + titleLabelStyle.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL); + titleLabelStyle.setPadding(tb.getPreferredH(), tb.getPreferredH(), tb.getPreferredH(), tb.getPreferredH()); + titleLabelStyle.setPaddingUnit(Style.UNIT_TYPE_PIXELS, Style.UNIT_TYPE_PIXELS, Style.UNIT_TYPE_PIXELS, Style.UNIT_TYPE_PIXELS); + titleLabelStyle.setMargin(0, 0, 0, 0); + +Initializes the image behind the title: + +![social-chat-tutorial-image-top.jpg](/blog/building-a-chat-app-with-codename-one-part-4/social-chat-tutorial-image-top.jpg) + +Notice we style it in code since we want it to be positioned in a very specific way and gain the size of the toolbar. Because +of that we use the padding from the toolbar to set the size properly. Notice that we explicitly state the padding unit otherwise +some platforms which default to millimeter padding might end up out of whack. + +We can do this sort of effect in several different ways but this specific approach with the “scaled to fill” option allows +the image to adapt nicely to device orientations without losing proportionality. + +There are several methods used within this block, we will go thru them from the easiest to the hardest: + + + private MultiButton createContactComponent(ContactData d) { + MultiButton mb = new MultiButton(); + mb.putClientProperty("uid", d.uniqueId); + mb.setTextLine1(d.name); + if(d.imageUrl != null) { + mb.setIcon(URLImage.createToStorage(userPlaceholder, "userPic" + d.uniqueId, d.imageUrl, URLImage.RESIZE_SCALE_TO_FILL)); + } else { + mb.setIcon(userPlaceholder); + } + mb.addActionListener((e) -> { + showChatForm(d, mb); + }); + return mb; + } + +An entry within the contacts list is just a multi-button without much funfair, we place the uid as a client property using the +`putClientProperty` call. This effectively allows us to place objects into a `Map` that exists within a `Component` that +way later on in the code when the button click is handled we can invoke `mb.getClientProperty("uid");` and get the unique +identifier represented by the button. That’s great for decoupling the application logic from the UI. + + + private void createMorphEffect(Label titleLabel) { + // animate the components out of the previous form if we are coming in from the login form + Form parent = Display.getInstance().getCurrent(); + if(parent.getUIID().equals("MainForm")) { + for(Component cmp : parent.getContentPane()) { + cmp.setX(parent.getWidth()); + } + + // moves all the components outside of the content pane to the right while fading them out over 400ms + parent.getContentPane().animateUnlayoutAndWait(400, 0); + parent.getContentPane().removeAll(); + + // we can't mutate a form into a component in another form so we need to convert the background to an image and then morph that + // this is especially easy since we already removed all the components + Label dummy = new Label(); + dummy.setShowEvenIfBlank(true); + dummy.setUIID("Container"); + dummy.setUnselectedStyle(new Style(parent.getUnselectedStyle())); + parent.setUIID("Form"); + + // special case to remove status bar on iOS 7 + parent.getTitleArea().removeAll(); + parent.setLayout(new BorderLayout()); + parent.addComponent(BorderLayout.CENTER, dummy); + parent.revalidate(); + + // animate the main panel to the new location at the top title area of the screen + dummy.setName("fullScreen"); + titleLabel.setName("titleImage"); + parent.setTransitionOutAnimator(MorphTransition.create(1100).morph("fullScreen", "titleImage")); + } + } + +The morph effect shows several effects when leaving the main form. Notice that it only applies when the main +UI is the source of the transition, which makes sense for most cases. E.g. we will have a different effect when +going back into the contacts form from a chat…​ + +We are showing two distinct effects here, in the first we animate the buttons outside of the screen, we do this by +placing them in their end location (outside of the screen to the right) then invoking the `animateUnlayoutAndWait` +which is the opposite of `animateLayoutAndWait`. Its designed to show exit animations like this and effectively +returns the components to their proper layout positions then animates them out while optionally fading them. + +Once the components are gone we remove them and then move the image into one big label and turn the UIID +of the form to a standard form. This is necessary for the morph transition which can only morph elements and not +the form itself. Normally this “trick” would work seamlessly but on iOS we have a `StatusBar` UIID at the top of the form +to push the application downwards and allow us to see the content of the status bar (battery etc.). A small hack +allows us to temporarily remove that component if it exists and prevents a “bounce” in the transition. + +Next we name the source/destination components for the morph transition and set it to the parent form. That’s +it, the morph transition does the rest of the work of animating the components into one another. + +The title area of the form is a standard `Toolbar`, though instead of using a standard title we used a custom component +comprised of layers to create the special effect. The `Toolbar` still folds automatically as we scroll and provides +all the standard effects. It also has a cool search feature that we will discuss in the next section. + + + private Component createTitleComponent(Form parent) { + // we want the toolbar to be completely transparent, since we created it on the layered pane (using the true + // argument in the constructor) it will flow in the UI + parent.getToolbar().setUIID("Container"); + + // we create 3 layers within the title, the region contains all the layers, the encspsulate includes the "me image" + // which we want to protrude under the title area layer + Container titleRegion = new Container(new LayeredLayout()); + Container titleEncapsulate = new Container(new BorderLayout()); + Container titleArea = new Container(new BorderLayout()); + + // since the Toolbar is now transparent we assign the title area UIID to one of the layers within and the look + // is preserved, we make it translucent though so we can see what's underneath + titleArea.setUIID("TitleArea"); + titleArea.getUnselectedStyle().setBgTransparency(128); + + // We customize the title completely using a component, the "title" is just a label with the Title UIID + Label title = new Label(parent.getTitle()); + title.setUIID("Title"); + titleArea.addComponent(BorderLayout.CENTER, title); + + // the search button allows us to search a large list of contacts rather easily + Button search = createSearchButton(parent, title, titleArea, titleRegion); + + // we package everything in a container so we can replace the title area with a search button as needed + Container cnt = new Container(new BoxLayout(BoxLayout.X_AXIS)); + titleArea.addComponent(BorderLayout.EAST, cnt); + cnt.addComponent(search); + + // this is the Me picture that protrudes downwards. We use a placeholder which is then replace by the URLImage + // with the actual image. Notice that createMaskAdapter allows us to not just scale the image but also apply + // a mask to it... + Label me = new Label(URLImage.createToStorage(roundPlaceholder, "userImage", imageURL, URLImage.createMaskAdapter(mask))); + me.setUIID("UserImage"); + + // the search icon and the "me" image are on two separate layers so we use a "dummy" component that we + // place in the search container to space it to the side and leave room for the "me" image + Label spacer = new Label(" "); + Container.setSameWidth(spacer, me); + cnt.addComponent(spacer); + + Container iconLayer = new Container(new BorderLayout()); + titleEncapsulate.addComponent(BorderLayout.NORTH, titleArea); + + titleRegion.addComponent(titleEncapsulate); + titleRegion.addComponent(iconLayer); + iconLayer.addComponent(BorderLayout.EAST, me); + + return titleRegion; + } + +The search button encapsulates a lot of functionality, effectively it replaces the title with a `TextField` that allows +us to type in a contact name. The cool part is the way in which we filter down the contacts to find the right entry +this is done using a data change listener and hiding the irrelevant entries dynamically. + +You can see this animation in action in this short video: + +All of this functionality is embedded directly into the code that creates the search button: + + + private Button createSearchButton(Form parent, Label title, Container titleArea, Container titleRegion) { + // we want the search feature to be based on the title style so it will "fit" but we need it to use the font defined + // by the icon font UIID so we merge both + Style s = new Style(title.getUnselectedStyle()); + Style iconFontStyle = UIManager.getInstance().getComponentStyle("IconFont"); + s.setFont(iconFontStyle.getFont().derive(s.getFont().getHeight(), Font.STYLE_PLAIN)); + FontImage searchIcon = FontImage.create(" ue806 ", s); + FontImage cancelIcon = FontImage.create(" ue81e ", s); + + // this is the actual search button, but we don't want it to have a border... + Button search = new Button(searchIcon); + search.setUIID("Label"); + + // the search box will be placed in the title area so we can type right into it. We make it look like a title but + // explicitly align it to the left for cases such as iOS where the title is centered by default + TextField searchBox = new TextField(); + searchBox.setUIID("Title"); + searchBox.getUnselectedStyle().setAlignment(Component.LEFT); + searchBox.getSelectedStyle().setAlignment(Component.LEFT); + + // the data change listener allows us to animate the data on every key press into the field + searchBox.addDataChangeListener((type, index) -> { + String text = searchBox.getText().toLowerCase(); + if(text.length() > 0) { + Dimension hidden = new Dimension(0, 0); + // iterates over the components, if a component matches its set to visible and its size is kept as default + // otherwise the component is hidden and set to occupy no space. + for(Component cmp : parent.getContentPane()) { + if(cmp instanceof MultiButton) { + String l1 = ((MultiButton)cmp).getTextLine1(); + if(l1.toLowerCase().indexOf(text) > -1) { + cmp.setPreferredSize(null); + cmp.setVisible(true); + } else { + cmp.setPreferredSize(hidden); + cmp.setVisible(false); + } + } + } + } else { + // no search string, show all the components by resetting the preferred size to default (thru null) and making them visible + for(Component cmp : parent.getContentPane()) { + cmp.setPreferredSize(null); + cmp.setVisible(true); + } + } + + // update the UI with an animation effect + parent.getContentPane().animateLayout(200); + }); + + // the action event is invoked when the button is pressed, this can have 2 separate states: during search/before search + search.addActionListener((e) -> { + if(search.getIcon() == searchIcon) { + // Starts the search operation by replacing the title with a text field and launching the native editing + search.setIcon(cancelIcon); + titleArea.replaceAndWait(title, searchBox, CommonTransitions.createCover(CommonTransitions.SLIDE_VERTICAL, true, 400)); + titleRegion.revalidate(); + Display.getInstance().editString(searchBox, searchBox.getMaxSize(), searchBox.getConstraint(), ""); + } else { + // if we are currently searching then cancel the search, return all items to visible and restore everything + search.setIcon(searchIcon); + for(Component cmp : parent.getContentPane()) { + cmp.setPreferredSize(null); + cmp.setVisible(true); + } + parent.getContentPane().animateLayoutAndWait(200); + search.setEnabled(true); + search.setVisible(true); + titleArea.replaceAndWait(searchBox, title, CommonTransitions.createCover(CommonTransitions.SLIDE_VERTICAL, true, 400)); + } + }); + return search; + } + +That’s a bit of a large method but its functionality is relatively simple. + +Last but not least this is the method that actually loads the contacts into place: + + + private void loadContacts(UserData data, InfiniteProgress ip, Container contactsContainer) { + // we sort the contacts by name which is pretty concise code thanks to Java 8 lambdas + Display.getInstance().scheduleBackgroundTask(() -> { + contacts = data.getContacts(); + CaseInsensitiveOrder co = new CaseInsensitiveOrder(); + Arrays.sort(contacts, (ContactData o1, ContactData o2) -> { + return co.compare(o1.name, o2.name); + }); + + Display.getInstance().callSerially(() -> { + if(recentContacts != null && recentContacts.size() > 0) { + Label recentHeader = new Label("Recent"); + recentHeader.setUIID("ContactsHeader"); + contactsContainer.addComponent(recentHeader); + + for(String cont : recentContacts) { + ContactData d = getContactById(cont); + contactsContainer.addComponent(createContactComponent(d)); + } + + Label allHeader = new Label("All Contacts"); + allHeader.setUIID("ContactsHeader"); + contactsContainer.addComponent(allHeader); + } + + contactsContainer.removeComponent(ip); + + for(ContactData d : contacts) { + contactsContainer.addComponent(createContactComponent(d)); + } + contactsContainer.revalidate(); + }); + }); + } + +There are several interesting things going on here. + + * We start by fetching and sorting the contacts in a low priority thread. We can just do something like `new Thread()` +which would be pretty similar but `scheduleBackgroundTask` recycles an existing thread which is slightly more +efficient. + + * We then return to the EDT using `callSerially` to add the components to the UI where we create an entry for +every component and revalidate to layout the UI + + * There is some code here for a “recent” entry which should priorities the contacts I’ve contacted recently, its +functionality that’s added in the local code base but isn’t fully implemented. + +Next time we’ll discuss the chat UI. + +Note: The original post neglected to include the body of the loadContacts method. + +### Other Posts In This Series + +This is a multi-part series of posts including the following parts: + + * [Part 1 – Initial UI](/blog/building-a-chat-app-with-codename-one-part-1.html) + + * [Part 2 – Login With Google](/blog/building-a-chat-app-with-codename-one-part-2.html) + + * [Part 3 – Login With Facebook](/blog/building-a-chat-app-with-codename-one-part-3.html) + + * [Part 4 – The Contacts Form](/blog/building-a-chat-app-with-codename-one-part-4.html) + + * [Part 5 – The Chat Form](/blog/building-a-chat-app-with-codename-one-part-5.html) + + * [Part 6 – Native Push & Finishing Up](/blog/building-a-chat-app-with-codename-one-part-6.html) + +You can check out the final source code of this tutorial [here](https://github.com/codenameone/codenameone-demos/tree/master/SocialChat). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Nigel Chomba** — August 6, 2015 at 12:58 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-4.html#comment-22128)) + +> I like this,i wish i could do this all day.Questions will come soon +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-4.html) + + +### **Diamond** — August 6, 2015 at 3:34 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-4.html#comment-21600)) + +> For the image placeholder, will it be possible to use fullName’s first character in Font Icon? For example, My name Diamond having “D” as the placeholder image just in case user doesn’t have a profile pic. +> +> “A small hack allows us to temporarily remove that component if it exists and prevents a “bounce” in the transition.” Are you referring to iOS status bar? If yes, any idea on how to temporarily hide the status bar? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-4.html) + + +### **Shai Almog** — August 7, 2015 at 5:02 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-4.html#comment-22345)) + +> Sure. You can do this dynamically e.g. Map mm =…; Then use an Image.create(int, int, int) and get the graphics from it to draw the character on it. Cache it in the map so you don’t have to do this all the time… +> +> Yes, the status bar. You can hide the entire title area by using getTitleArea().setPreferredSize(new Dimension(0, 0))); That will also hide the status bar. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-4.html) + + +### **♫☆ Alex Goretoy ☭ ☁** — August 8, 2015 at 1:57 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-4.html#comment-22330)) + +> This is great! Thanks so much. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-4.html) + + +### **ugochukwu** — August 12, 2015 at 9:41 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-4.html#comment-22275)) + +> shai am still desprately waiting for next series +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-4.html) + + +### **ugochukwu** — August 12, 2015 at 9:42 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-4.html#comment-22083)) + +> this is a great tutorial series! thanks somuch +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-4.html) + + +### **Omar Suleiman** — March 6, 2017 at 5:42 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-4.html#comment-23140)) + +> I want to ask about chat group room is supported with codename one, or one chat per application without allowing user to create new group and chatting. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-4.html) + + +### **Shai Almog** — March 7, 2017 at 6:35 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-4.html#comment-23352)) + +> This specific demo is for 1 on 1 conversations but the platform has no such restrictions. Check out this post covering a 3rd party who built a pretty nice looking whatsapp clone using Codename One: [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-4.html) + + +### **Francesco Galgani** — November 28, 2017 at 10:03 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-4.html#comment-23606)) + +> A simple question that is not related to the tutorial itself: how did you record the small video of the app? Thank you +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-4.html) + + +### **Shai Almog** — November 29, 2017 at 6:40 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-4.html#comment-21474)) + +> With Android it’s really easy. My device has a screen capture app that’s shipped by the vendor and allows recording video so this is really trivial (it’s an OPO with the original cyanogen so probably not applicable). +> But all modern android devices allow you to capture video via ADB see [https://developer.android.c…]() +> +> For iOS I used to use Reflection but those a*holes essentially want to charge again for Relection II after I paid for 1. Turns out you don’t need that at all and it’s a huge waste! +> +> On a Mac just connect the device and launch Quick Time. Then launch recording from quicktime and you will literally see the device screen and you can record everything then cut the parts of the video you want/don’t want. Very cool and useful! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-4.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/building-a-chat-app-with-codename-one-part-5.md b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-5.md new file mode 100644 index 0000000000..b35d51c137 --- /dev/null +++ b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-5.md @@ -0,0 +1,662 @@ +--- +title: Building A Chat App With Codename One Part 5 +slug: building-a-chat-app-with-codename-one-part-5 +url: /blog/building-a-chat-app-with-codename-one-part-5/ +original_url: https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-5.html +aliases: +- /blog/building-a-chat-app-with-codename-one-part-5.html +date: '2015-08-16' +author: Shai Almog +--- + +![Header Image](/blog/building-a-chat-app-with-codename-one-part-5/chat-app-tutorial-chat-form-5.png) + +The chat UI is what we’ve been working at and in todays post we are going to build exactly that! + +Even better…​ We’ll integrate with Pubnub to make the app almost fully functional as a rudimentary chat app, which +is pretty spectacular. In this section we’ll cover UI, storage (externalization), Pubnub & its JSON API…​ We’ll +also use `InteractionDialog` to show notifications of incoming messages…​ + +Before we get started you will need to login to [pubnub.com](http://www.pubnub.com) and sign up for an account +where you will get two ID’s necessary when subscribing and pushing. + +We also need to install the Pubnub cn1lib and its dependencies, place the following files in the lib directory +under the project hierarchy: +[BouncyCastleCN1Lib.cn1lib](/files/BouncyCastleCN1Lib.cn1lib), +[Pubnub-CodeNameOne-3.7.4.cn1lib](/files/Pubnub-CodeNameOne-3.7.4.cn1lib) & +[json.cn1lib](/files/json.cn1lib). + +Once you placed the files into the lib directory right click the project and select “Codename One→Refresh Libs”. +This will install the libraries into your classpath and allow you to use them while enjoying features such as code +completion etc. + +You will also need images for the chat bubbles specifically [this one](/img/blog/chat-bubble-left.png): + +![chat-bubble-left.png](/blog/building-a-chat-app-with-codename-one-part-5/chat-bubble-left.png) + +And [this one](/img/blog/chat-bubble-right.png): + +![chat-bubble-right.png](/blog/building-a-chat-app-with-codename-one-part-5/chat-bubble-right.png) + +### Theme Changes + +We need to start by setting up the theme elements that we will use later on for the bubble chat, we effectively need the +two speech bubbles mentioned above to map to the UIID’s `BubbleMe` & `BubbleThem`. So we start by adding the +theme element `BubbleMe` where we set transparency to 0 (since we will use an image border) and the foreground +color to white `ffffff`: + +![BubbleMe UIID step 1](/blog/building-a-chat-app-with-codename-one-part-5/chat-app-tutorial-chat-form-1.png) + +Then we need to set the padding for the speech bubble to the text won’t be on top of the speech arrow or the border +itself. We set the padding in millimeters to keep the design portable and set 3mm on the left side to leave room +for the arrow: + +![BubbleMe UIID step 2: padding](/blog/building-a-chat-app-with-codename-one-part-5/chat-app-tutorial-chat-form-2.png) + +Now we need to cut the image border using the image border wizard and the `chat-bubble-left.png` image we +mentioned earlier. Notice that we take the lines as close as possible to each other to make the border work: + +![BubbleMe UIID step 3: Border](/blog/building-a-chat-app-with-codename-one-part-5/chat-app-tutorial-chat-form-3.png) + +We need to do the exact same thing for the `BubbleThem` UIID with the only difference being the `chat-bubble-right.png` +and larger padding on the right side instead of the left side. + +![BubbleMe UIID step 4: BubbleThem](/blog/building-a-chat-app-with-codename-one-part-5/chat-app-tutorial-chat-form-4.png) + +### The Message Class + +Up until now we used mostly inner classes in a single file which makes things rather simple for a demo. But now +we’ll add a new `Message` class that will represent a message sent/received and encapsulate the JSON parsing +logic required for PubNub communication. + +This class is `Externalizeable` which means we can store it into storage relatively easily. That’s important to keep +past messages in the conversation in place: + + + public class Message implements Externalizable { + + private long time; + private String senderId; + private String recepientId; + private String picture; + private String name; + private String message; + + /** + * Required default constructor for externalizable to work... + */ + public Message() {} + + public Message(String senderId, String recepientId, String picture, String name, String message) { + this.senderId = senderId; + this.recepientId = recepientId; + this.picture = picture; + this.name = name; + this.message = message; + } + + public Message(JSONObject obj) { + try { + time = Long.parseLong(obj.getString("time")); + senderId = obj.getString("fromId"); + recepientId = obj.getString("toId"); + message = obj.getString("message"); + name = obj.getString("name"); + picture = obj.getString("pic"); + } catch (JSONException ex) { + // will this ever happen? + Log.e(ex); + } + } + + public JSONObject toJSON() { + JSONObject obj = createJSONObject("fromId", senderId, + "toId", recepientId, + "name", name, + "pic", picture, + "time", Long.toString(System.currentTimeMillis()), + "message", message); + return obj; + } + + /** + * Helper method to create a JSONObject + */ + JSONObject createJSONObject(String... keyValues) { + try { + JSONObject o = new JSONObject(); + for(int iter = 0 ; iter < keyValues.length ; iter += 2) { + o.put(keyValues[iter], keyValues[iter + 1]); + } + return o; + } catch(JSONException err) { + // will this ever happen? + err.printStackTrace(); + } + return null; + } + + + @Override + public int getVersion() { + return 1; + } + + @Override + public void externalize(DataOutputStream out) throws IOException { + out.writeLong(time); + Util.writeUTF(senderId, out); + Util.writeUTF(recepientId, out); + Util.writeUTF(picture, out); + Util.writeUTF(name, out); + Util.writeUTF(message, out); + } + + @Override + public void internalize(int version, DataInputStream in) throws IOException { + time = in.readLong(); + senderId = Util.readUTF(in); + recepientId = Util.readUTF(in); + picture = Util.readUTF(in); + name = Util.readUTF(in); + message = Util.readUTF(in); + } + + @Override + public String getObjectId() { + return "Message"; + } + + public long getTime() { + return time; + } + + public String getSenderId() { + return senderId; + } + + public String getRecepientId() { + return recepientId; + } + + public String getPicture() { + return picture; + } + + public String getName() { + return name; + } + + public String getMessage() { + return message; + } + } + +This class is pretty simple, notice a few interesting things about externalization: + + * We use `Util.writeUTF` and `Util.readUTF` which adds support for null strings by writing/reading a boolean first +to indicate if the value is null…​ + + * `getObjectId` is a hardcoded string and not something like `getClass().getName()`. Using class name is a very +common mistake which is why I’m mentioning it. It will work in the simulator and seem to work during development +but will fail with upgrades since class names are obfuscated on some devices and might result in serious problems. + + * We also need the default constructor for externalization support. + +### Global Variables & Initialization + +To get started we need to add some global variables: + + + private Pubnub pb; + private Image roundedMeImage; + private final WeakHashMap roundedImagesOfFriends = new WeakHashMap<>(); + +These should be pretty self explanatory, pubnub represents the API for push. The roundedMeImage is a cached +version of the image we created earlier. It allows us to reuse that UI element in different forms. The `WeakHashMap` +allows us to cache pictures of friends without triggering a memory leak…​ + +We also need to add this to the `init` method: + + + public void init(Object context) { + ... + Util.register("Message", Message.class); + ... + } + +This effectively registers the `Message` class into the system so when we de-serialize it on loading we can recognize the +class. Developers often make the mistake of using the static initializer code in the class to register itself. That’s +problematic since the class might not be loaded before it is read. + +### Listening To Messages + +We’d like to start listening to incoming messages the moment we are logged in and this happens in the +`showContactsForm` so we can add this call to the top of that method: + + + void showContactsForm(UserData data) { + listenToMessages(); + ... + } + + private void listenToMessages() { + try { + pb = new Pubnub("pub-c-*********-****-****-****-*************", "sub-c-*********-****-****-****-*************"); + pb.subscribe(tokenPrefix + uniqueId, new Callback() { + @Override + public void successCallback(String channel, Object message, String timetoken) { + Display.getInstance().callSerially(() -> { + respond(new Message((JSONObject)message)); + }); + } + }); + } catch(PubnubException err) { + Log.e(err); + Dialog.show("Error", "There was a communication error: " + err, "OK", null); + } + } + +Subscribing to messages thru pubnub is trivial, we convert the JSON object received by response and send it to the method +that posts the response. Notice that we wrap the call in a call serially since the response is received off the EDT +and processing it should probably be on the EDT as we will interact with the UI. We’ll get deeper into the response +processing later…​ + +PubNub works by providing message queues that you can subscribe to and publish to, imagine this like email +where you can subscribe to a mailing list and handle incoming messages. However, if you aren’t listening a message +might be gone…​ They do provide an option for a persistent queue that will keep the last 100 messages for you which +can be very useful for this sort of app! + +The architecture we are going to use is pretty simple, every person just listens on his own unique ID. That way +to send a message to a specific person just publish to his queue and that person can reply by publishing to yours. + +We include sender details in every message thus allowing us to distinguish among the people we are chatting with. + +### The Chat Form + +![BubbleMe UIID step 4: BubbleThem](/blog/building-a-chat-app-with-codename-one-part-5/chat-app-tutorial-chat-form-5.png) + +That’s a screenshot from a chat on my Android device…​ The chat form is created via this method which is a bit +verbose but relatively simple. + + + void showChatForm(ContactData d, Component source) { + Form chatForm = new Form(d.name); + + // this identifies the person we are chatting with, so an incoming message will know if this is the right person... + chatForm.putClientProperty("cid", tokenPrefix + d.uniqueId); + chatForm.setLayout(new BorderLayout()); + Toolbar tb = new Toolbar(); + final Container chatArea = new Container(new BoxLayout(BoxLayout.Y_AXIS)); + chatArea.setScrollableY(true); + chatArea.setName("ChatArea"); + chatForm.setToolBar(tb); + chatForm.setBackCommand(new Command("Contacts") { + @Override + public void actionPerformed(ActionEvent evt) { + source.getComponentForm().showBack(); + } + }); + + // Provides the ability to swipe the screen to go back to the previous form + SwipeBackSupport.bindBack(chatForm, (args) -> { + return source.getComponentForm(); + }); + + // Gets a rounded version of our friends picture and caches it + Image roundedHimOrHerImage = getRoundedFriendImage(d.uniqueId, d.imageUrl); + + // load the stored messages and add them to the form + java.util.List messages = (java.util.List)Storage.getInstance().readObject(tokenPrefix + d.uniqueId); + if(messages != null) { + for(Message m : messages) { + if(m.getRecepientId().equals(tokenPrefix + uniqueId)) { + respondNoLayout(chatArea, m.getMessage(), roundedHimOrHerImage); + } else { + sayNoLayout(chatArea, m.getMessage()); + } + } + } + + // to place the image on the right side of the toolbar we just use a command that does nothing... + Command himOrHerCommand = new Command("", roundedHimOrHerImage); + tb.addCommandToRightBar(himOrHerCommand); + + // we type the message to the chat partner in the text field on the south side + TextField write = new TextField(30); + write.setHint("Write to " + d.name); + chatForm.addComponent(BorderLayout.CENTER, chatArea); + chatForm.addComponent(BorderLayout.SOUTH, write); + + // the action listener for the text field creates a message object, converts it to JSON and publishes it to the listener queue + write.addActionListener((e) -> { + String text = write.getText(); + final Component t = say(chatArea, text); + + // we make outgoing messages translucent to indicate that they weren't received yet + t.getUnselectedStyle().setOpacity(120); + write.setText(""); + + final Message messageObject = new Message(tokenPrefix + uniqueId, tokenPrefix + d.uniqueId, imageURL, fullName, text); + JSONObject obj = messageObject.toJSON(); + + pb.publish(tokenPrefix + d.uniqueId, obj, new Callback() { + @Override + public void successCallback(String channel, Object message) { + // a message was received, we make it opauqe and add it to the storage + t.getUnselectedStyle().setOpacity(255); + addMessage(messageObject); + } + + @Override + public void errorCallback(String channel, PubnubError error) { + chatArea.removeComponent(t); + chatArea.revalidate(); + Dialog.show("Error", "Connection error message wasn't sent", "OK", null); + } + }); + }); + + chatForm.show(); + } + +There are several things of interest in the above method: + + * chatArea contains all the chat entries, notice we give it a name explicitly! This is useful later on, when a chat +message arrives if we are in the chat form we’d like to add the message into that form…​ + + * We use a client property on the chat form `cid` to store the user we are chatting with. That way if we are chatting +with a different contact an incoming message from another contact won’t get pushed into that conversation. + + * The chat area is scrollable and the text field is in the south. Notice that since we set the layout to border layout +the default scrollability of the form’s content pane was implicitly disabled. + + * We used a command that does nothing to place the image of the contact on the toolbar, its simpler than the effect +we had in the previous form but still pretty nice. + + * We load the existing messages if available from storage using the object externalization capability of the `Storage` +class. + + * By default we have a `say` and `respond` methods that encapsulate the bubble chat component creation. However, +they do a nice incoming animation that we don’t want when a new message arrives so we use a version that doesn’t +do the layout for both during construction of the form + + * This is all the code you need to work with PubNub! That’s pretty cool…​ Everything else is handled for us. + +There are several important methods used by this method and we’ll go over them one by one: + + + private Component say(Container chatArea, String text) { + Component t = sayNoLayout(chatArea, text); + t.setY(chatArea.getHeight()); + t.setWidth(chatArea.getWidth()); + t.setHeight(40); + chatArea.animateLayoutAndWait(300); + chatArea.scrollComponentToVisible(t); + return t; + } + + private Component sayNoLayout(Container chatArea, String text) { + SpanLabel t = new SpanLabel(text); + t.setIcon(roundedMeImage); + t.setTextBlockAlign(Component.LEFT); + t.setTextUIID("BubbleMe"); + chatArea.addComponent(t); + return t; + } + +These two methods essentially print out what we have to say as a chat bubble. The latter method just sets the span label +icon to my picture (which we made previously) and aligns the block to the left. It also sets the bubble UIID we created +previously to the text portion of the span label. + +The former method makes the bubble animate from the bottom by setting the size/location of the component and then doing an +animate layout that flows it into the right place. + +The basic respond methods are practically identical with some minor changes: + + + private void respond(Container chatArea, String text, Image roundedHimOrHerImage) { + Component answer = respondNoLayout(chatArea, text, roundedHimOrHerImage); + answer.setX(chatArea.getWidth()); + answer.setWidth(chatArea.getWidth()); + answer.setHeight(40); + chatArea.animateLayoutAndWait(300); + chatArea.scrollComponentToVisible(answer); + } + + private Component respondNoLayout(Container chatArea, String text, Image roundedHimOrHerImage) { + SpanLabel answer = new SpanLabel(text); + answer.setIcon(roundedHimOrHerImage); + answer.setIconPosition(BorderLayout.EAST); + answer.setTextUIID("BubbleThem"); + answer.setTextBlockAlign(Component.RIGHT); + chatArea.addComponent(answer); + return answer; + } + +The main difference here is the UIID and alignment to the right, also you will notice that we pass the image of the speaker +as an argument since it might not be available…​ + +But the big difference is that those methods aren’t invoked for incoming chat entries directly, instead we use: + + + private void respond(Message m) { + String clientId = (String)Display.getInstance().getCurrent().getClientProperty("cid"); + addMessage(m); + EncodedImage rounded = getRoundedFriendImage(m.getSenderId(), m.getPicture()); + if(clientId == null || !clientId.equals(m.getSenderId())) { + // show toast, we aren't in the chat form... + InteractionDialog toast = new InteractionDialog(); + toast.setUIID("Container"); + toast.setLayout(new BorderLayout()); + + SpanButton messageButton = new SpanButton(m.getMessage()); + messageButton.setIcon(rounded); + + toast.addComponent(BorderLayout.CENTER, messageButton); + int h = toast.getPreferredH(); + toast.show(Display.getInstance().getDisplayHeight() - h - 10, 10, 10, 10); + UITimer uit = new UITimer(() -> { + toast.dispose(); + }); + uit.schedule(3000, false, Display.getInstance().getCurrent()); + + messageButton.addActionListener((e) -> { + uit.cancel(); + toast.dispose(); + showChatForm(getContactById(m.getSenderId()), Display.getInstance().getCurrent()); + }); + } else { + Container chatArea = getChatArea(Display.getInstance().getCurrent().getContentPane()); + respond(chatArea, m.getMessage(), rounded); + } + } + +As you recall from the original subscribe call, this is the method invoked internally as a message arrives from pubnub. +At that point we are logged in but we might be in a chat with someone else or we might even be in the contacts form +in one of those two cases the id will be either null or different to the current ID so we will show an interaction dialog effect +that you can see in the video below, otherwise we just invoke the regular respond method we saw above: + +The interaction dialog is just a container placed on the layered pane. Because of that it doesn’t block input +like a regular dialog would, so if I’m chatting with someone when a message arrives this shouldn’t cause a problem. +We use a `UITimer ` to automatically dispose of the dialog, the `UITimer` is convenient since its invoked on the EDT +unlike a regular timer so the effort is minimal. + +We use a button for the notification so we can click it and go directly to the chat window as is shown at the end of the +video above. + + + private Container getChatArea(Container cnt) { + String n = cnt.getName(); + if(n != null && n.equals("ChatArea")) { + return cnt; + } + + for(Component cmp : cnt) { + if(cmp instanceof Container) { + Container cur = getChatArea((Container)cmp); + if(cur != null) { + return cur; + } + } + } + return null; + } + +You’ll notice we used `getChatArea` above as a simple tool to abstract the chat area. We could also save the reference +to chatArea in the class itself but that might risk a memory leak so this is simpler. I’m not too concerned about threads +or race conditions since pretty much everything is on the EDT. + + + private EncodedImage getRoundedFriendImage(String uid, String imageUrl) { + EncodedImage roundedHimOrHerImage = roundedImagesOfFriends.get(uid); + if(roundedHimOrHerImage == null) { + roundedHimOrHerImage = URLImage.createToStorage(roundPlaceholder, "rounded" + uid, imageUrl, URLImage.createMaskAdapter(mask)); + roundedImagesOfFriends.put(uid, roundedHimOrHerImage); + } + return roundedHimOrHerImage; + } + +We mentioned this method much earlier, its relatively simple so I glossed over it. Its roughly identical to the “me picture” +we had in the previous posts just applied to pictures of friends. + + + private void addMessage(Message m) { + String personId; + + // if this is a message to me then store based on sender otherwise store based on recepient + if(m.getRecepientId().equals(tokenPrefix + uniqueId)) { + personId = m.getSenderId(); + } else { + personId = m.getRecepientId(); + } + java.util.List messages = (java.util.List)Storage.getInstance().readObject(personId); + if(messages == null) { + messages = new ArrayList(); + } + messages.add(m); + Storage.getInstance().writeObject(personId, messages); + } + +The last method of interest stores the message data into storage. We use an array list of messages which is pretty +simple. + +### Potential Improvements + +Next time we’ll discuss push messages, in this version of the app messages that don’t arrive get lost…​ That’s a problem. +For that case we’ll use push notification from the OS to alert the other side. + +We can also enable storage for the message queue thus allowing messages to remain cached until the next time the +user logs in. + +There is also an issue if the user logs in from multiple devices he won’t see the chat history and one device +will grab incoming messages that might not reach another…​ This can be easily solved with a central database +architecture or possibly persistent queues in pubnub (although I don’t have experience there). + +Other potential improvements can be: + + * Facebook’s invite friends and share buttons + + * Unread count and icon badging for iOS + + * Notification bar entries + + * Attachments and more complex data + +All of those should be pretty trivial. We’ll publish the full source code and the project with the next update of this +series and let you guys play with it. + +### Other Posts In This Series + +This is a multi-part series of posts including the following parts: + + * [Part 1 – Initial UI](/blog/building-a-chat-app-with-codename-one-part-1.html) + + * [Part 2 – Login With Google](/blog/building-a-chat-app-with-codename-one-part-2.html) + + * [Part 3 – Login With Facebook](/blog/building-a-chat-app-with-codename-one-part-3.html) + + * [Part 4 – The Contacts Form](/blog/building-a-chat-app-with-codename-one-part-4.html) + + * [Part 5 – The Chat Form](/blog/building-a-chat-app-with-codename-one-part-5.html) + + * [Part 6 – Native Push & Finishing Up](/blog/building-a-chat-app-with-codename-one-part-6.html) + +You can check out the final source code of this tutorial [here](https://github.com/codenameone/codenameone-demos/tree/master/SocialChat). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Lanre Makinde** — August 17, 2015 at 6:37 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-5.html#comment-22339)) + +> Whoaoooooo. U guys are so far ahead. For you to despite your busy schedule have time for this kinda tutorials. Although I will wish to see login through twitter handled in your tutorial as well. Thanks great guys, great work. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-5.html) + + +### **salah Alhaddabi** — November 19, 2016 at 1:34 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-5.html#comment-23150)) + +> Dear Shai, I have tried the chat app up until now without the pubnub functionality. I have copied the exact same code from here and also missing pieces from gethub. When I use it on the simulator and clock on google login I login ok. But when I try to get friends I get an error even when the token is valid. I immediately get 400 error code when I try to use facebook login. I have tried the app on my android device S7 and I get a message the socialChat app has closed when I click on google login. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-5.html) + + +### **Shai Almog** — November 20, 2016 at 6:13 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-5.html#comment-23092)) + +> Try running with the device connected with a cable and DDMS to see the output. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-5.html) + + +### **salah Alhaddabi** — November 20, 2016 at 6:34 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-5.html#comment-23174)) + +> Dear Shai, +> +> I have downloaded the apk file and start android studoi and opened the apk file in android studo and connected my samsung to PC with a USB cable but not sure what to do next as nothing appears in the console when the application fails. Can you please instruct me on how to go about this debugging?? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-5.html) + + +### **Shai Almog** — November 21, 2016 at 4:52 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-5.html#comment-23025)) + +> You don’t need to open the APK in Android studio. Just run the app as usual on the device and in android studio select the DDMS tool. This will open a special console on the bottom where you can pick your device and look thru the logs. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-5.html) + + +### **salah Alhaddabi** — November 21, 2016 at 6:59 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-5.html#comment-23036)) + +> Dear Shai, +> +> This is what I get from the DDMS log when I run SocialChat. +> +> Initially after installing the app I get google login asking me to allow SocialChat to access my google account. Then I get transfered to the initial screen and stay on the login form without opening the contact form. The When I try to click again on the google login it tells me the “Unfortunately, SocialChat has stopped”. This is what I get when I try to do the google login again while connected my device through USB and use the DDMS tool: +> +> 11-21 22:29:15.822: E/AndroidRuntime(27804): at com.codename1.social.GoogleImpl$a.a([GoogleImpl.java]():187) +> 11-21 22:29:15.822: E/AndroidRuntime(27804): at com.codename1.social.GoogleImpl$a.doInBackground([GoogleImpl.java]():179) +> +> As for the Facebook login, I login successfuly but the contact form is empty with no contacts loaded even though I am sure many of my contacts are online. +> +> Your help is much appreciated. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-5.html) + + +### **Shai Almog** — November 22, 2016 at 4:49 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-5.html#comment-23218)) + +> As explained in the article Facebook doesn’t provide access to all your contacts. It only provides access to contacts who installed the app… +> +> There is more output in the Google login which should probably clarify that. Also make sure you are building with API level 21 to workaround this issue: [https://github.com/codename…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-5.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/building-a-chat-app-with-codename-one-part-6.md b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-6.md new file mode 100644 index 0000000000..a7a5f34140 --- /dev/null +++ b/docs/website/content/blog/building-a-chat-app-with-codename-one-part-6.md @@ -0,0 +1,565 @@ +--- +title: Building A Chat App With Codename One Part 6 +slug: building-a-chat-app-with-codename-one-part-6 +url: /blog/building-a-chat-app-with-codename-one-part-6/ +original_url: https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html +aliases: +- /blog/building-a-chat-app-with-codename-one-part-6.html +date: '2015-09-16' +author: Shai Almog +--- + +![Header Image](/blog/building-a-chat-app-with-codename-one-part-6/chat-app-tutorial-chat-form-5.png) + +This will be the last installment of this tutorial which was pretty complete in the previous section already. We might +have additional installments mostly for covering enhancements such as “invite a friend” and other similar capabilites +but this is probably as good a place as any to finish the app and let you try it live. + +### Native Push + +Up until now we used PubNub to implement the push functionality which is excellent especially if you opt for the +paid option which can also persist messages and offers quite a few additional perks for an app such as this. +However, when the app isn’t running PubNub can’t push anything and in that case we need an OS native push to +send the message. + +The obvious question would be “why not use OS native push for everything?”. + +Its possible to do so but OS native push isn’t as flexible, portable, fast or reliable as PubNub. Its painful to work with +and the user can intentionally or inadvertently break it by disagreeing to an OS prompt etc…​ As you will see from the +rest of the tutorial where we fallback to native OS push when PubNub can’t reach our target, its no panacea. + +#### The PushCallback Interface + +We start by implementing the `PushCallback` interface in our main class, this must be the actual main class or +push won’t work: + + + public class SocialChat implements PushCallback { + +Then we need to implement the following methods: + + + @Override + public void push(String value) { + // its a JSON message, otherwise its a notice to the user + if(value.startsWith("{") || value.startsWith("[")) { + try { + JSONObject obj = new JSONObject(value); + + // this is still early since we probably didn't login yet so add the messages to the list of pending messages + java.util.List pendingMessages = (java.util.List)Storage.getInstance().readObject("pendingMessages"); + if(pendingMessages == null) { + pendingMessages = new ArrayList<>(); + } + Message m = new Message(obj); + pendingMessages.add(m); + Storage.getInstance().writeObject("pendingMessages", pendingMessages); + addMessage(m); + } catch(JSONException err) { + err.printStackTrace(); + } + } + } + + @Override + public void registeredForPush(String deviceId) { + } + + @Override + public void pushRegistrationError(String error, int errorCode) { + } + +You will notice the following things here: + + * We don’t really need anything in the `registeredForPush` or `pushRegistrationError`. Since we use PubNub even +if push fails the app will still work fine. `registeredForPush` is normally used to get the push key (which isn’t the argument +passed to that method its the `Push.getPushKey()`) and send it to your servers so you can trigger a push to this device. +Since here we don’t have a real server we have no use for that method. + + * The `push` method does the heavy lifting of handling push messages. It can be called anytime and accepts +the push callbacks. It receives both visible and hidden push messages and decides what to do with them based +on their content. + + * We don’t show the message during the push callback. It will be invoked before the user had time to login and +so we want to just store the `Message` objects and have them processed later. We still add them to the general +store in case the user decides to kill the app before actually logging in + +#### New Constants & Registration + +We need to add the following variables to the class to continue, I masked and changed the values. We’ll go over +them one by one: + + + private static final String PUSH_TOKEN = "********-****-****-****-*************"; + private static final String GCM_SENDER_ID = "99999999999999"; + private static final String GCM_SERVER_API_KEY = "******************-********************"; + private static final boolean ITUNES_PRODUCTION_PUSH = false; + private static final String ITUNES_PRODUCTION_PUSH_CERT = "https://domain.com/linkToP12Prod.p12"; + private static final String ITUNES_PRODUCTION_PUSH_CERT_PASSWORD = "ProdPassword"; + private static final String ITUNES_DEVELOPMENT_PUSH_CERT = "https://domain.com/linkToP12Dev.p12"; + private static final String ITUNES_DEVELOPMENT_PUSH_CERT_PASSWORD = "DevPassword"; + +`PUSH_TOKEN` is the easiest, just login to Codename One and select the account tab. It should appear just +above the `Update Details` button. If it isn’t there try logging out and logging back in. + +You can get the `GCM_SENDER_ID` & `GCM_SERVER_API_KEY` from Google very easily. This assumes you +followed our instructions to create a Google project in part 2 of the tutorial. If you skipped that (because you +didn’t need a G+ account login) just make sure to create a new project in the Google API console based on the +instructions in part 2. + +To generate those just go to and click “pick a platform”: + +![click ](/blog/building-a-chat-app-with-codename-one-part-6/chat-app-tutorial-gcm-1.png) + +Select “Android App” + +![Select ](/blog/building-a-chat-app-with-codename-one-part-6/chat-app-tutorial-gcm-2.png) + +Enter the details for the app and the package + +![Enter the details for the app and the package](/blog/building-a-chat-app-with-codename-one-part-6/chat-app-tutorial-gcm-3.png) + +Click the “Cloud Messaging” option then click the “Enable Google Cloud Messaging” button + +![Click the ](/blog/building-a-chat-app-with-codename-one-part-6/chat-app-tutorial-gcm-4.png) + +You should now have the values for both `GCM_SENDER_ID` & `GCM_SERVER_API_KEY` as illustrated below + +![You should now have the values for both GCM_SENDER_ID & GCM_SERVER_API_KEY as illustrated below](/blog/building-a-chat-app-with-codename-one-part-6/chat-app-tutorial-gcm-5.png) + +Thanks to our new certificate wizard generating the iOS portion of these flags is now a complete breeze! + +We just go thru the certificate wizard and check the flag to enable push: + +![Enable push in the wizard](https://www.codenameone.com/img/blog/chat-app-tutorial-apns-1.png) + +Once you finish that wizard and check the enable push flag make sure that the iOS section also has the “Include Push” +flag checked. There is a bug in the current plugin where it isn’t enabled automatically. + +You should receive instructions to include push by email which should include links that you can just paste into place +and passwords. This should be pretty seamless. + +### Other Code Changes + +When you push to a device you need to have the device key which is a unique identifier of the device to which you +want to send a push. Unfortunately since we don’t have a server in place we need somehow pass this key from the +person we are chatting with. The trick is to embed this key into the Message object and thus update it when we receive +a message, this means that we can only send a push message to a person who wrote to us in the past. Not a bad +feature all and all but still a limitation…​ + +To do that we need to do these two simple changes to the `Message` class: + + + public Message(JSONObject obj) { + try { + time = Long.parseLong(obj.getString("time")); + senderId = obj.getString("fromId"); + recepientId = obj.getString("toId"); + message = obj.getString("message"); + name = obj.getString("name"); + picture = obj.getString("pic"); + + // update the push id for the given user + if(obj.has("pushId")) { + String pushId = obj.getString("pushId"); + if(pushId != null) { + Preferences.set("pid-" + senderId, pushId); + } + } + } catch (JSONException ex) { + // will this ever happen? + Log.e(ex); + } + } + + public JSONObject toJSON() { + String pushId = Push.getPushKey(); + if(pushId != null) { + JSONObject obj = createJSONObject("fromId", senderId, + "toId", recepientId, + "name", name, + "pic", picture, + "time", Long.toString(System.currentTimeMillis()), + "message", message, "pushId", pushId); + return obj; + } + JSONObject obj = createJSONObject("fromId", senderId, + "toId", recepientId, + "name", name, + "pic", picture, + "time", Long.toString(System.currentTimeMillis()), + "message", message); + return obj; + } + +This effectively adds a push ID to every message we send if its available and updates a contacts push ID for usage +later. + +Now we need to register for push, in the end of the `start()` method in `SocialChat.java` we add: + + + // let the login form show before we register the push so the permission screen doesn't appear on a white + // background + Display.getInstance().callSerially(() -> { + // registering for push after the UI appears + Hashtable args = new Hashtable(); + args.put(com.codename1.push.Push.GOOGLE_PUSH_KEY, GCM_SENDER_ID); + Display.getInstance().registerPush(args, true); + }); + +We do it this way to let the UI appear first. + +Previously in the `showChatForm` method we just sent a message thru PubNub, now we want there to be a fallback +that will send the message via push. To do that we need to know that the message wasn’t received by the other +side. To discover that we now add a back message in PubNub called “ACK” which will acknowledge the receipt +of a message, if an ACK isn’t received that means the message should be sent thru native push…​ To do that we add +the class field: + + + /** + * Includes messages that received ACK notices from the receiver + */ + private ArrayList pendingAck = new ArrayList<>(); + +We remove ACK’s automatically in the `listenToMessages` method as such: + + + private void listenToMessages() { + try { + pb = new Pubnub("pub------------------------------", "sub-------------------------------"); + pb.subscribe(tokenPrefix + uniqueId, new Callback() { + @Override + public void successCallback(String channel, Object message, String timetoken) { + if(message instanceof String) { + pendingAck.remove(channel); + return; + } + Message m = new Message((JSONObject)message); + pb.publish(tokenPrefix + m.getSenderId(), "ACK", new Callback() {}); + Display.getInstance().callSerially(() -> { + addMessage(m); + respond(m); + }); + } + }); + } catch(PubnubException err) { + Log.e(err); + Dialog.show("Error", "There was a communication error: " + err, "OK", null); + } + } + +In the `showChatForm` method we need to fallback to push, this is a bit of a large method so I’m only posting +the relevant section here: + + + final Message messageObject = new Message(tokenPrefix + uniqueId, tokenPrefix + d.uniqueId, imageURL, fullName, text); + JSONObject obj = messageObject.toJSON(); + + String pid = Preferences.get("pid-" + tokenPrefix + d.uniqueId, null); + if(pid != null) { + // if we have a push address for the contact we can send them a push if they aren't reachable... + UITimer timeout = new UITimer(() -> { + if(pendingAck.contains(tokenPrefix + d.uniqueId)) { + pendingAck.remove(tokenPrefix + d.uniqueId); + // send two messages, one hidden with the data as JSON for parsing on the client + // the other one visible with the text that should appear to the user who isn't running + // the app, this will allow him to launch the app and then receive the hidden message immediately + // within the app + String cert = ITUNES_DEVELOPMENT_PUSH_CERT; + String pass = ITUNES_DEVELOPMENT_PUSH_CERT_PASSWORD; + if(ITUNES_PRODUCTION_PUSH) { + cert = ITUNES_PRODUCTION_PUSH_CERT; + pass = ITUNES_PRODUCTION_PUSH_CERT_PASSWORD; + } + if(Push.sendPushMessage(PUSH_TOKEN, text + ";" + obj.toString(), + ITUNES_PRODUCTION_PUSH, GCM_SERVER_API_KEY, cert, pass, 3, pid)) { + t.getUnselectedStyle().setOpacity(255); + t.repaint(); + addMessage(messageObject); + } else { + chatArea.removeComponent(t); + chatArea.revalidate(); + Dialog.show("Error", "We couldn't reach " + d.name + " thru push", "OK", null); + } + } + }); + + timeout.schedule(10000, false, write.getComponentForm()); + if(!pendingAck.contains(tokenPrefix + d.uniqueId)) { + pendingAck.add(tokenPrefix + d.uniqueId); + } + } + +The way this works is rather simple: + + 1. If we have a push id then we create a 10 second timer + + 2. When the timer elapses we check if the pendingAck is still pending, if so we need to fall back to push + + 3. We have the device push key from the `Message` class above so sending the push message is pretty easy +relatively + + 4. We send a type 3 push which includes both a visible and invisible payload separated by a colon (;). +The visible payload is just the text of the message whereas the invisible payload is the JSON string we want to add to the message database + +And that’s pretty much it for the chat app! + +### Final Word + +You can check out the final source code of this tutorial [here](https://github.com/codenameone/codenameone-demos/tree/master/SocialChat). + +When I started off with this tutorial I wasn’t yet familiar with the Parse integration for Codename One. +After playing with it quite a bit and being blown away by it I would have architected this whole app on +top of it and simplified quite a bit in the process. It would also allow me to track push ID’s keep messages +in place and remove some of the issues with going back and forth between PubNub/native push. + +I’d still use PubNub without a doubt! Its amazing and very convenient for fast push networking. I think that combining +it with Parse would have made this a much better app. + +Login via Google/Facebook etc. was probably the most painful part of the app and I’m including push notification +within the set of pains. While it is much simpler than it used to be and is simpler than the native/web versions I +think the main problem is in the networks opacity and desire to keep the developers close. The pain is less on +our side and more on the tedium of creating apps and passing values to Facebook/Google. The APK hash key +is just painful, there were things such as “invite a friend” which I just avoided because of the tedium. + +I might do a rewrite with those thoughts in mind but I’m more inclined to redo this as a cn1lib rather than an app. +The main motivation being end user support for apps, so developers can communicate with users over issues by integrating +a single cn1lib into our app. I’m not sure I’ll have time to dig into something like that but I think it should be +relatively easy since most of the big pieces (push, cloud storage etc.) are already handled by these great 3rd party +services. + +### Other Posts In This Series + +This is a multi-part series of posts including the following parts: + + * [Part 1 – Initial UI](/blog/building-a-chat-app-with-codename-one-part-1.html) + + * [Part 2 – Login With Google](/blog/building-a-chat-app-with-codename-one-part-2.html) + + * [Part 3 – Login With Facebook](/blog/building-a-chat-app-with-codename-one-part-3.html) + + * [Part 4 – The Contacts Form](/blog/building-a-chat-app-with-codename-one-part-4.html) + + * [Part 5 – The Chat Form](/blog/building-a-chat-app-with-codename-one-part-5.html) + + * [Part 6 – Native Push & Finishing Up](/blog/building-a-chat-app-with-codename-one-part-6.html) + +You can check out the final source code of this tutorial [here](https://github.com/codenameone/codenameone-demos/tree/master/SocialChat). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — September 18, 2015 at 1:50 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-22478)) + +> Nice to see the concluding ‘edition’ of this series. I’ve scanned quickly through the post and I have a few questions: +> +> 1\. Can you please explain what you mean by visible and hidden push? I had a look at the Push Javadoc and didn’t seem to find any sendPushMessage() method meeting the signature you used. +> +> 2\. You say that the PushCallback must be implemented by the main class. +> (a) Why is that needed? +> (b) For a GUI builder application this would be the StateMachine class right? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + + +### **Shai Almog** — September 18, 2015 at 3:34 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-21601)) + +> 1\. Both iOS and Android allow delivering a payload that is hidden so we can just update application state from the server. +> Hidden push is just push type==2 and type 3 means we are sending two push entries in a single operation: [http://www.codenameone.com/…]() +> +> The javadocs should be updated this is related to the new push architecture: [http://www.codenameone.com/…]() +> +> 2\. The main class represents the lifecycle (start, stop etc.) and that is effectively where push resides in the native platform. So we mapped it to there. A main class exists even in a GUI builder app, its not the statemachine class. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + + +### **Chidiebere Okwudire** — September 24, 2015 at 7:15 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-22232)) + +> Clear. Thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + + +### **Hristo Vrigazov** — July 19, 2016 at 6:42 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-22969)) + +> Cloned the chat, and the following is shown just after I login with Google: +> +> java.lang.NullPointerException +> at com.codename1.ui.html.HTMLComponent.newLine([HTMLComponent.java]():1872) +> at com.codename1.ui.html.HTMLComponent.processTag([HTMLComponent.java]():3289) +> at com.codename1.ui.html.HTMLComponent.processTag([HTMLComponent.java]():3273) +> at com.codename1.ui.html.HTMLComponent.processTag([HTMLComponent.java]():3273) +> at com.codename1.ui.html.HTMLComponent.processTag([HTMLComponent.java]():3273) +> at com.codename1.ui.html.HTMLComponent.rebuildPage([HTMLComponent.java]():1757) +> at com.codename1.ui.html.HTMLComponent.documentReady([HTMLComponent.java]():1143) +> at com.codename1.ui.html.HTMLComponent.streamReady([HTMLComponent.java]():1058) +> at com.codename1.components.WebBrowser$4$1.readResponse([WebBrowser.java]():138) +> at com.codename1.io.ConnectionRequest.performOperation([ConnectionRequest.java]():483) +> at com.codename1.io.NetworkManager$[NetworkThread.run](:282) +> at [com.codename1.impl.Codename…](:176) +> +> What could be the problem? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + + +### **Shai Almog** — July 20, 2016 at 4:26 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-22682)) + +> Make sure you are running under Java 8. You are falling back to use code that doesn’t have access to the webkit browser. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + + +### **Hristo Vrigazov** — July 20, 2016 at 2:01 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-22902)) + +> Thanks, that was the problem! Awesome tutorials by the way +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + + +### **Ayushi Gupta** — December 7, 2016 at 10:32 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-23207)) + +> Ayushi Gupta says: +> +> followed all the instructions & this is what happened …. +> +> ant -f C:\Users\Administrator\Documents\NetBeansProjects\SocialChat1 -[Dnb.internal.action.name]()=run run +> No GUI Entries available +> init: +> Deleting: C:UsersAdministratorDocumentsNetBeansProjectsSocialChat1build[built-jar.properties]() +> deps-jar: +> Updating property file: C:UsersAdministratorDocumentsNetBeansProjectsSocialChat1build[built-jar.properties]() +> Compile is forcing compliance to the supported API’s/features for maximum device compatibility. This allows smaller +> code size and wider device support +> compile: +> run: +> Dec 08, 2016 3:56:07 AM java.util.prefs.WindowsPreferences +> WARNING: Could not open/create prefs root node SoftwareJavaSoftPrefs at root 0x80000002. Windows RegCreateKeyEx(…) returned error code 5. +> java.lang.ClassNotFoundException: com.mycompany.myapp.MyApplication +> at java.net.URLClassLoader.findClass([URLClassLoader.java]():381) +> at java.lang.ClassLoader.loadClass([ClassLoader.java]():424) +> at sun.misc.Launcher$AppClassLoader.loadClass([Launcher.java]():331) +> at java.lang.ClassLoader.loadClass([ClassLoader.java]():357) +> at java.lang.ClassLoader.findSystemClass([ClassLoader.java]():1004) +> at com.codename1.impl.javase.ClassPathLoader.findClass([ClassPathLoader.java]():100) +> at com.codename1.impl.javase.ClassPathLoader.loadClass([ClassPathLoader.java]():50) +> at java.lang.Class.forName0(Native Method) +> at java.lang.Class.forName([Class.java]():264) +> at com.codename1.impl.javase.Executor$[1.run](:86) +> at java.awt.event.InvocationEvent.dispatch([InvocationEvent.java]():311) +> at java.awt.EventQueue.dispatchEventImpl([EventQueue.java]():756) +> at java.awt.EventQueue.access$500([EventQueue.java]():97) +> at java.awt.EventQueue$[3.run](:709) +> at java.awt.EventQueue$[3.run](:703) +> at java.security.AccessController.doPrivileged(Native Method) +> at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege([ProtectionDomain.java]():76) +> at java.awt.EventQueue.dispatchEvent([EventQueue.java]():726) +> at java.awt.EventDispatchThread.pumpOneEventForFilters([EventDispatchThread.java]():201) +> at java.awt.EventDispatchThread.pumpEventsForFilter([EventDispatchThread.java]():116) +> at java.awt.EventDispatchThread.pumpEventsForHierarchy([EventDispatchThread.java]():105) +> at java.awt.EventDispatchThread.pumpEvents([EventDispatchThread.java]():101) +> at java.awt.EventDispatchThread.pumpEvents([EventDispatchThread.java]():93) +> at [java.awt.EventDispatchThrea…](:82) +> Java Result: 1 +> BUILD SUCCESSFUL (total time: 2 seconds) +> +> Please help this is 2nd time i m trying to make this chat app +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + + +### **Shai Almog** — December 8, 2016 at 6:18 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-22990)) + +> Shai Almog says: +> +> It clearly says: ClassNotFoundException: com.mycompany.myapp.MyApplication +> You created a project and then modified the package/class name after the fact without fixing it everywhere. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + + +### **Ayushi Gupta** — December 8, 2016 at 4:16 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-22932)) + +> Ayushi Gupta says: +> +> now how can i fix it ….when i was making first one…my application was used by me but now Social Chat and Message are 2 classes as mentioned in tutorials …..so now what to do…..& plz tell me that where i need to fix it Plzz let me know how to fix it +> +> i guess i have done that….but now there is java:108 indicating problem in roundPlaceholder = EncodedImage.createFromImage(userPlaceholder.scaled(mask.getWidth(), mask.getHeight()).applyMask(mask.createMask()), false); +> this is what happened +> Compile is forcing compliance to the supported API’s/features for maximum device compatibility. This allows smaller +> code size and wider device support +> compile: +> run: +> Dec 09, 2016 2:30:38 AM java.util.prefs.WindowsPreferences +> WARNING: Could not open/create prefs root node SoftwareJavaSoftPrefs at root 0x80000002. Windows RegCreateKeyEx(…) returned error code 5. +> java.lang.NullPointerException +> at com.mycompany.myapp.Gchat.init([Gchat.java]():108) +> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) +> at sun.reflect.NativeMethodAccessorImpl.invoke([NativeMethodAccessorImpl.java]():62) +> at sun.reflect.DelegatingMethodAccessorImpl.invoke([DelegatingMethodAccessorImp…]():43) +> at java.lang.reflect.Method.invoke([Method.java]():498) +> at com.codename1.impl.javase.Executor$1$[1.run](:81) +> at com.codename1.ui.Display.processSerialCalls([Display.java]():1152) +> at com.codename1.ui.Display.mainEDTLoop([Display.java]():969) +> at [com.codename1.ui.RunnableWr…](:120) +> at [com.codename1.impl.Codename…](:176) +> plz let me know how to fix it +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + + +### **Ayushi Gupta** — December 9, 2016 at 4:10 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-23284)) + +> Ayushi Gupta says: +> +> i guess i have fixed it …but now i got this +> Dec 09, 2016 9:37:28 PM java.util.prefs.WindowsPreferences +> WARNING: Could not open/create prefs root node SoftwareJavaSoftPrefs at root 0x80000002. Windows RegCreateKeyEx(…) returned error code 5. +> java.lang.NullPointerException +> at com.mycompany.myapp.Gchat.init([Gchat.java]():108) +> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) +> at sun.reflect.NativeMethodAccessorImpl.invoke([NativeMethodAccessorImpl.java]():62) +> at sun.reflect.DelegatingMethodAccessorImpl.invoke([DelegatingMethodAccessorImp…]():43) +> at java.lang.reflect.Method.invoke([Method.java]():498) +> at com.codename1.impl.javase.Executor$1$[1.run](:81) +> at com.codename1.ui.Display.processSerialCalls([Display.java]():1152) +> at com.codename1.ui.Display.mainEDTLoop([Display.java]():969) +> at [com.codename1.ui.RunnableWr…](:120) +> at [com.codename1.impl.Codename…](:176) +> Java Result: 1 +> Plzzz let me know how to fix it +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + + +### **Ayushi Gupta** — December 9, 2016 at 5:44 pm ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-23293)) + +> Ayushi Gupta says: +> +> i fixed it …but now when i press signin with google after asking my e-mail and password it goes to codenameone page and says PAGE NOT FOUND and when i press signin with facebook it says “Can’t Load URL: The domain of this URL isn’t included in the app’s domains. To be able to load this URL, add all domains and subdomains of your app to the App Domains field in your app settings” +> Pllzzz let me know how to fix it +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + + +### **Shai Almog** — December 10, 2016 at 6:16 am ([permalink](https://www.codenameone.com/blog/building-a-chat-app-with-codename-one-part-6.html#comment-23000)) + +> Shai Almog says: +> +> That usually means you got a login callback with success and that the page is no longer relevant. Notice that the experience on the device differs greatly from the experience in the simulator since you will use the native login there. +> +> Make sure you defined the app correctly and have the right calls within the login success/fail. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-a-chat-app-with-codename-one-part-6.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/building-codename-one-from-source-maven-edition.md b/docs/website/content/blog/building-codename-one-from-source-maven-edition.md new file mode 100644 index 0000000000..0533870d8a --- /dev/null +++ b/docs/website/content/blog/building-codename-one-from-source-maven-edition.md @@ -0,0 +1,127 @@ +--- +title: Building Codename One From Source – Maven Edition +slug: building-codename-one-from-source-maven-edition +url: /blog/building-codename-one-from-source-maven-edition/ +original_url: https://www.codenameone.com/blog/building-codename-one-from-source-maven-edition.html +aliases: +- /blog/building-codename-one-from-source-maven-edition.html +date: '2021-04-21' +author: Steve Hannah +description: Learn how to build Codename One from source and use this "local" version + in your Codename One projects. +--- + +Learn how to build Codename One from source and use this "local" version in your Codename One projects. + +## Tip + +> This post is targeted at experienced Codename One users. If you haven’t built an app with Codename One before, I recommend you start with this [Getting Started tutorial](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html) (for Java) or [this tutorial](https://shannah.github.io/cn1app-archetype-kotlin-template/getting-started.html) (for Kotlin). + +One of the benefits of [moving to Maven](https://www.codenameone.com/blog/moving-to-maven.html) is improved project hygiene. It is now trivial to build Codename One from source. + +In this video, I show you how to build Codename One from source and use this “local” version in your Codename One projects. + +### TLDW (Too Long Didn’t Watch) + +Here’s the gist of what happens in the video. + +1. Clone the [Codename One repository](https://github.com/codenameone/CodenameOne), then run mvn install in the maven subdirectory: + +```bash + + git clone https://github.com/codenameone/CodenameOne +cd CodenameOne/maven +mvn install + + +``` + +This will take a few minutes, but at the end of the tunnel you should see “SUCCESS” as shown below: + +![mvn-install-success](https://www.codenameone.com/wp-content/uploads/2021/04/mvn-install-success.png) + +2. Clone the [cn1-maven-archetypes repository](https://github.com/shannah/cn1-maven-archetypes), then run mvn install in its root directory: + +```bash + + git clone https://github.com/shannah/cn1-maven-archetypes +cd cn1-maven-archetypes +mvn install + + +``` + +This will take another minute or so, but at the end of the tunnel you should see “SUCCESS”: + +![mvn-install-archetypes-success](https://www.codenameone.com/wp-content/uploads/2021/04/mvn-install-archetypes-success.png) + +After completing these steps, Codename One will be installed in the local maven repository. A key point I make in this video is the version number of the sources that I checked out of Github. If you are cloning the project from the master branch, then the version will usually be a SNAPSHOT version. E.g. 7.0.21-SNAPSHOT. This is a Maven convention. Release versions will not have the **-SNAPSHOT** suffix. + + +In the video, you can see that the version number is “7.0.21-SNAPSHOT”. + +## Using the Local Version in Your Application Project + +Now that Codename One is installed in your local Maven repo, you can use that version in your application instead of the release version. + +I demonstrate this in the video by creating a new project with the [Codename One initializr](https://start.codenameone.com/). + +![cn1-intializr](https://www.codenameone.com/wp-content/uploads/2021/04/cn1-intializr.png) + +## Tip + +> Check out my [Video tutorial on Codename One initializr](https://sjhannah.medium.com/preview-online-tool-to-generate-ios-android-app-starter-project-c9f27c47850b) if you haven’t seen it yet. + +After downloading and extracting the project, I open its pom.xml file and and look for the and properties: + +![cn1-version-properties](https://www.codenameone.com/wp-content/uploads/2021/04/cn1-version-properties.png) + +I then change these to point to the version that I installed into my local maven repository: 7.0.21-SNAPSHOT. + +![cn1-version-updated](https://www.codenameone.com/wp-content/uploads/2021/04/cn1-version-updated.png) + +### Why Build From Source? + +Because you can, and because it is the first step toward taking control of your own destiny. It gives you early access to features that may not be available on Maven Central, and it also enables you to make your own changes, and potentially contribute them to the Codename One core. + +### Getting Started + +If you haven’t built an app yet, it’s easy to get started. Just go to [Codename One initializr](https://start.codenameone.com/) and press “Download”. You could be up and running in only a few minutes. + +If you want to dig deeper into Codename One’s Maven support, check out the [Codename One Maven Developers Guide](https://shannah.github.io/codenameone-maven-manual/). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved here for historical context. New discussion happens in the Discussion section below._ + + +### **Dave Dyer** — July 20, 2023 at 10:07 pm ([permalink](https://www.codenameone.com/blog/building-codename-one-from-source-maven-edition.html#comment-24563)) + +> Dave Dyer says: +> +> something is out of date. in codenameone\maven, mvn install +> +> [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project +> java-runtime: Compilation failure: Compilation failure: +> [ERROR] Source option 5 is no longer supported. Use 7 or later. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-codename-one-from-source-maven-edition.html) + + +### **Dave Dyer** — July 21, 2023 at 7:35 pm ([permalink](https://www.codenameone.com/blog/building-codename-one-from-source-maven-edition.html#comment-24564)) + +> Dave Dyer says: +> +> This is somehow related to the java version in use. I fixed this by +> downgrading my default java from java-16 to and older jdk, jdk-1.8 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbuilding-codename-one-from-source-maven-edition.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/button-lists.md b/docs/website/content/blog/button-lists.md new file mode 100644 index 0000000000..716f453b3d --- /dev/null +++ b/docs/website/content/blog/button-lists.md @@ -0,0 +1,139 @@ +--- +title: Button Lists +slug: button-lists +url: /blog/button-lists/ +original_url: https://www.codenameone.com/blog/button-lists.html +aliases: +- /blog/button-lists.html +date: '2018-12-04' +author: Shai Almog +--- + +![Header Image](/blog/button-lists/new-features-4.jpg) + +I wrote in the past about the [problems in the List class](/blog/avoiding-lists.html), so I won’t rehash them here. However, the ideas behind list are still valuable. One such idea is the list model which allows us to separate the state from the view. Unfortunately the renderer architecture makes this hard to implement for most developers and limits the flexibility of the API. + +To leverage this idea with the easier to use layout/container hierarchy we introduced `ButtonList` and its subclasses: `CheckBoxList`, `RadioButtonList` & `SwitchList`. + +We also added a new `MultipleSelectionListModel` which extends the `ListModel` with multi-selection capabilities. This allows us to use a set of buttons as we would use a list and also generate them from data more easily. + +In the code below we show two lists that use the same model. Changes to the checkboxes reflect instantly in the switch and vice versa: + + + Form hi = new Form("Button Lists", new BorderLayout()); + SwitchList switchList = new SwitchList(new DefaultListModel("Red", "Green", "Blue", "Indigo")); + switchList.addActionListener(e->{ + Log.p("Selected indices: "+Arrays.toString(switchList.getMultiListModel().getSelectedIndices())); + }); __**(1)** + switchList.setScrollableY(true); + Button clearSelections = new Button("Clear"); + clearSelections.addActionListener(e -> + switchList.getMultiListModel().setSelectedIndices()); + + Button addOption = new Button("Add Option"); + addOption.addActionListener(e -> { __**(2)** + callSerially(()->{ + TextField val = new TextField(); + Command res = Dialog.show("Enter label", val, new Command("OK")); + switchList.getMultiListModel().addItem(val.getText()); + + }); + }); + RadioButtonList layoutSelector = new RadioButtonList(new DefaultListModel("Flow", "X", "Y", "2-Col Table", "3-Col Table", "2 Col Grid", "3 Col Grid")); + layoutSelector.addActionListener(e->{ __**(3)** + boolean yScroll = true; + switch (layoutSelector.getModel().getSelectedIndex()) { + case 0: + switchList.setLayout(new FlowLayout()); + break; + case 1: + switchList.setLayout(BoxLayout.x()); + yScroll = false; + break; + case 2: + switchList.setLayout(BoxLayout.y()); + break; + case 3: + switchList.setLayout(new TableLayout(switchList.getComponentCount()/2+1, 2)); + break; + case 4: + switchList.setLayout(new TableLayout(switchList.getComponentCount()/3+1, 3)); + break; + case 5: + switchList.setLayout(new GridLayout(2)); + break; + case 6: + switchList.setLayout(new GridLayout(3)); + } + switchList.setScrollableX(!yScroll); + switchList.setScrollableY(yScroll); + switchList.animateLayout(300); + }); + CheckBoxList checkBoxList = new CheckBoxList(switchList.getMultiListModel()); __**(4)** + checkBoxList.addActionListener(e-> + System.out.println("CheckBox actionEvent. "+Arrays.toString(checkBoxList.getMultiListModel().getSelectedIndices()))); + hi.add(BorderLayout.NORTH, layoutSelector); + hi.add(BorderLayout.CENTER, BoxLayout.encloseY(checkBoxList, switchList)); + hi.add(BorderLayout.SOUTH, GridLayout.encloseIn(2, addOption, clearSelections)); + hi.show(); + +__**1** | Instead of binding multiple listeners we can bind a listener to the list itself and get the selections +---|--- +__**2** | It’s easy to add options like clear selection and add option thanks to the structure of the list model +__**3** | This list uses a layout as it’s in-effect just a `Container` +__**4** | The `CheckBoxList` uses the same model as the `SwitchList` + +![Demo of the button list](/blog/button-lists/button-list.png) + +Figure 1. Demo of the button list classes +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — December 8, 2018 at 11:14 am ([permalink](https://www.codenameone.com/blog/button-lists.html#comment-24102)) + +> Great! However, in this example, there is an issue: the “Add Option” works fine with iOS skin, but it doesn’t work as expected on Android skin (because it’s necessary to change the layout to see the new added Button). I done tests with “[iPhoneX.skin]()” and “[GooglePixel2.skin]()” +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbutton-lists.html) + + +### **Francesco Galgani** — December 8, 2018 at 11:14 am ([permalink](https://www.codenameone.com/blog/button-lists.html#comment-23875)) + +> Francesco Galgani says: +> +> Why do you use the callSerially in the ActionListener of the addOption button? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbutton-lists.html) + + +### **Francesco Galgani** — December 8, 2018 at 11:14 am ([permalink](https://www.codenameone.com/blog/button-lists.html#comment-21539)) + +> Francesco Galgani says: +> +> To create the DefaultListModel, you used a list of Strings as args. Is it possible to bind the DefaultListModel with a list of BooleanProperty as args? It could be an interesting enhancement to seamlessly map the user selections in a ButtonList with a PropertyBusinessObject. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbutton-lists.html) + + +### **Shai Almog** — December 8, 2018 at 1:46 pm ([permalink](https://www.codenameone.com/blog/button-lists.html#comment-24105)) + +> Shai Almog says: +> +> The strings map to the labels matching the entries, the models map to the selection which is an integer or set of integers. A boolean would be a problem as you can’t get the labels from the boolean values. However, it would probably be easy to map this to boolean property objects as the model selection logic can be a great place to do that. +> +> I use the callSerially because of the [Dialog.show]() that follows. It allows the event queue to flush before we block it. +> +> There is an issue which wasn’t noticeable to me because of the different animations for the dialog showing. We need a hi.revalidate() in the end of the callSerially invocation. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fbutton-lists.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/cache-sorted-properties-preferences-listener.md b/docs/website/content/blog/cache-sorted-properties-preferences-listener.md new file mode 100644 index 0000000000..e08290886e --- /dev/null +++ b/docs/website/content/blog/cache-sorted-properties-preferences-listener.md @@ -0,0 +1,107 @@ +--- +title: Cache, Sorted Properties and Preference Listener +slug: cache-sorted-properties-preferences-listener +url: /blog/cache-sorted-properties-preferences-listener/ +original_url: https://www.codenameone.com/blog/cache-sorted-properties-preferences-listener.html +aliases: +- /blog/cache-sorted-properties-preferences-listener.html +date: '2016-12-12' +author: Shai Almog +--- + +![Header Image](/blog/cache-sorted-properties-preferences-listener/new-features-5.jpg) + +We’ve had quite a few interesting features land last week and didn’t get a chance to cover them. First we have +access to the OS’s caches directory where you can store files that you don’t really need as cache. Both iOS & +Android have such a directory and files stored there might be purged without notice if the OS runs out of space. + +This is a good place to store files you don’t really need such as images or downloads you just need for “right now”. + +To use this we added two new API’s to `FileSystemStorage`: + + + public boolean hasCachesDir(); + public String getCachesDir(); + +Normally we would use `hasCachesDir()` to indicate whether the caches dir should be used and if not we would just +write fallback code that uses the home directory. Notice that the caches dir will only work on iOS & Android and +will return false everywhere else at this time. We plan to integrate this into various features of Codename One +to make usage easier e.g. `URLImage` and an upcoming feature I’ll discuss later in the week. + +### Sorted Properties + +Starting with this release properties are sorted and no longer add a timestamp comment every time they are saved. + +The comment makes no sense as it never provided any value beyond the file date/time stamp. The sorting of the +properties solves a major problem with the properties API. Saving is inconsistent. + +We did this to fix a bug in our settings tool where `codenameone_settings.properties` gets jumbled whenever you +save because the order of the hashmap is based on the `hashCode` method. This way the order is consistent and +remains that way when checking the file into version control. + +Fixing this for our application only would solve our problem but I’m guessing the jumbled properties that you need +to sort thru every time doesn’t make sense for any application ever…​ +This way you can have a consistent human understandable order for machine saved properties. Notice this is a +“write only” feature so you don’t need to sort your properties for parsing to work. + +### Preferences Listener + +We got a [pull request](https://github.com/codenameone/CodenameOne/pull/1980) that allows you to observe +the `Preferences` API. This is useful if you have some generic code that relies on this API for settings. + +This request lets you do something like: + + + Preferences.addPreferenceListener("MySetting", (pref, oldValue, newValue) -> Log.p(pref + " changed to " + newValue)); + +This allows you to monitor changes to preferences individually and apply them instantly when they happen +without the need to wrap all calls to preferences in a generic method. This observability allows different parts +of your application to remain decoupled while supporting a single setting attribute. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — December 13, 2016 at 11:46 pm ([permalink](https://www.codenameone.com/blog/cache-sorted-properties-preferences-listener.html#comment-23066)) + +> bryan says: +> +> So should use something like: +> +> FileSystemStorage.getInstance().openOutputStream(FileSystemStorage.getInstance().getChacheDir() + “/ ” + fname); +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcache-sorted-properties-preferences-listener.html) + + +### **Shai Almog** — December 14, 2016 at 5:12 am ([permalink](https://www.codenameone.com/blog/cache-sorted-properties-preferences-listener.html#comment-23232)) + +> Shai Almog says: +> +> Not quite. getCachesDir() will be null for cases where there is no such directory. E.g. on the simulator we don’t have a caches dir so this will fail. So you need a strategy that will no how to deal with a null cache directory. E.g. this is new code for a feature I’m blogging about later this week: +> +> private String getCacheFileName() { +> String root; +> if(FileSystemStorage.getInstance().hasCachesDir()) { +> root = FileSystemStorage.getInstance().getCachesDir() + “cn1ConCache/”; +> } else { +> root = FileSystemStorage.getInstance().getAppHomePath()+ “cn1ConCache/”; +> } +> FileSystemStorage.getInstance().mkdir(root); +> return root + Base64.encodeNoNewline(createRequestURL().getBytes()).replace(‘/’, ‘-‘).replace(‘+’, ‘_’); +> } +> +> This will use the caches dir if it’s available but fallback to normal if not. +> +> Also notice that directories in Codename One should always end with the / character so the + “/” is redundant. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcache-sorted-properties-preferences-listener.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/calendar-small-changes.md b/docs/website/content/blog/calendar-small-changes.md new file mode 100644 index 0000000000..1f6703da81 --- /dev/null +++ b/docs/website/content/blog/calendar-small-changes.md @@ -0,0 +1,91 @@ +--- +title: Calendar & Small Changes +slug: calendar-small-changes +url: /blog/calendar-small-changes/ +original_url: https://www.codenameone.com/blog/calendar-small-changes.html +aliases: +- /blog/calendar-small-changes.html +date: '2014-02-11' +author: Shai Almog +--- + +![Header Image](/blog/calendar-small-changes/calendar-small-changes-1.png) + + + + + +![Picture](/blog/calendar-small-changes/calendar-small-changes-1.png) + + + + +I’ve been working a bit with Kapila and Andreas on a +[ +Calendar project for Codename One +](http://code.google.com/p/codenameone-calendar/) +to be used as a +[ +cn1lib +](http://codenameone.com/cn1libs.html) +(working is a strong word I’ve mostly just bossed them around and didn’t really do much, they did all the work). Its a pretty ambitious project since Calendar API’s are so fragmented and problematic, in fact no cross platform tool I’m familiar with has anything remotely close to a working Calendar API. + + +If this is something important/dear to your heart feel free to pitch in and try to improve the implementation, file issues etc. + + + + + + +In other news we’ve Improved facebook support on iOS to use the device native login where possible, this was actually implemented incorrectly and was brought to our attention. + + + + + +Last week we had one of the most annoying bugs I think we ever had to deal with. It seems that in some iPhones (only iPhones never iPads) camera capture crashes when saving the photo. We were never able to reproduce this on any of our devices but a customer was getting this consistently on his, eventually he lent us his personal iPhone and we spent half a day debugging this, turns out this is a known issue and the solution is: reboot the device… Ugh. + + + + +We no longer have a device that reproduces this issue but we’ve incorporated one of the suggested workarounds for this issue into the code so we hope it works around that iOS bug. If it doesn’t and you are seeing crashes on devices when taking a picture with the current builds let us know! + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — February 26, 2014 at 2:49 pm ([permalink](https://www.codenameone.com/blog/calendar-small-changes.html#comment-21704)) + +> Anonymous says: +> +> Is this library finished or there is still some works going on? +> +> Thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcalendar-small-changes.html) + + +### **Anonymous** — February 26, 2014 at 3:54 pm ([permalink](https://www.codenameone.com/blog/calendar-small-changes.html#comment-21923)) + +> Anonymous says: +> +> It seems development has slowed down a little. As far as I understand the basic functionality Andreas and Kapilla need is working for them. I suggest you ask this on the forum where they can see it and respond with more information. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcalendar-small-changes.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/callserially-the-edt-invokeandblock-part-1.md b/docs/website/content/blog/callserially-the-edt-invokeandblock-part-1.md new file mode 100644 index 0000000000..c5904bb794 --- /dev/null +++ b/docs/website/content/blog/callserially-the-edt-invokeandblock-part-1.md @@ -0,0 +1,109 @@ +--- +title: CallSerially The EDT & InvokeAndBlock (Part 1) +slug: callserially-the-edt-invokeandblock-part-1 +url: /blog/callserially-the-edt-invokeandblock-part-1/ +original_url: https://www.codenameone.com/blog/callserially-the-edt-invokeandblock-part-1.html +aliases: +- /blog/callserially-the-edt-invokeandblock-part-1.html +date: '2014-10-18' +author: Shai Almog +--- + +![Header Image](/blog/callserially-the-edt-invokeandblock-part-1/callserially-the-edt-invokeandblock-part-1-1.png) + + + + +[ +![Picture](/blog/callserially-the-edt-invokeandblock-part-1/callserially-the-edt-invokeandblock-part-1-1.png) +](/img/blog/old_posts/callserially-the-edt-invokeandblock-part-1-large-2.png) + + + + + + +We last explained some of the concepts behind the EDT in 2008 so its high time we wrote about it again, there is a section about it in the developer guide as well as in the courses on Udemy but since this is the most important thing to understand in Codename One it bares repeating. + +One of the nice things about the EDT is that many of the concepts within it are similar to the concepts in pretty much every other GUI environment (Swing/FX, Android, iOS etc.). So if you can understand this explanation this might help you when working in other platforms too. + +Codename One can have as many threads as you want, however there is one thread created internally in Codename One named “EDT” for Event Dispatch Thread. This name doesn’t do the thread justice since it handles everything including painting etc. + +You can imagine the EDT as a loop such as this: + +while(codenameOneRunning) { + +performEventCallbacks(); + +performCallSeriallyCalls(); + +drawGraphicsAndAnimations(); + +sleepUntilNextEDTCycle(); + +} + +The general rule of the thumb in Codename One is: Every time Codename One invokes a method its probably on the EDT (unless explicitly stated otherwise), every time you invoke something in Codename One it should be on the EDT (unless explicitly stated otherwise). + +There are a few notable special cases: + +1\. NetworkManager/ConnectionRequest – use the network thread internally and not the EDT. However they can/should be invoked from the EDT. + +2\. BrowserNavigationCallback – due to its unique function it MUST be invoked on the native browser thread. + +3\. Displays invokeAndBlock/startThread – create completely new threads. + +Other than those pretty much everything is on the EDT. If you are unsure you can use the Display.isEDT method to check whether you are on the EDT or not. + +** +EDT Violations +** + +You can violate the EDT in two major ways: + +1\. Call a method in Codename One from a thread that isn’t the EDT thread (e.g. the network thread or a thread created by you). + +2\. Do a CPU intensive task (such as reading a large file) on the EDT – this will effectively block all event processing, painting etc. making the application feel slow. + +Luckily we have a tool in the simulator: the EDT violation detection tool. This effectively prints a stack trace to suspect violations of the EDT. Its not fool proof and might land your with false positives but it should help you with some of these issues which are hard to detect. + +So how do you prevent an EDT violation? + +To prevent abuse of the EDT thread (slow operations on the EDT) just spawn a new thread using either new Thread(), Display.startThread or invokeAndBlock (more on that later). + +Then when you need to broadcast your updates back to the EDT you can use callSerially or callSeriallyAndWait. + +** +CallSerially +** + +callSerially invokes the run() method of the runnable argument it receives on the Event Dispatch Thread. This is very useful if you are on a separate thread but is also occasionally useful when we are on the EDT and want to postpone actions to the next cycle of the EDT (more on that next time). + +callSeriallyAndWait is identical to call serially but it waits for the callSerially to complete before returning. For obvious reasons it can’t be invoked on the EDT. + +In the second part of this mini tutorial I will discuss invokeAndBlock and why we might want to use callSerially when we already are on the EDT. + +** +Update: +** +You can read part 2 of this post +[ +here +](http://www.codenameone.com/blog/callserially-the-edt-invokeandblock-part-2) +. + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/callserially-the-edt-invokeandblock-part-2.md b/docs/website/content/blog/callserially-the-edt-invokeandblock-part-2.md new file mode 100644 index 0000000000..a78c05c8a5 --- /dev/null +++ b/docs/website/content/blog/callserially-the-edt-invokeandblock-part-2.md @@ -0,0 +1,201 @@ +--- +title: CallSerially The EDT & InvokeAndBlock (Part 2) +slug: callserially-the-edt-invokeandblock-part-2 +url: /blog/callserially-the-edt-invokeandblock-part-2/ +original_url: https://www.codenameone.com/blog/callserially-the-edt-invokeandblock-part-2.html +aliases: +- /blog/callserially-the-edt-invokeandblock-part-2.html +date: '2014-11-09' +author: Shai Almog +--- + +![Header Image](/blog/callserially-the-edt-invokeandblock-part-2/callserially-the-edt-invokeandblock-part-2-1.png) + + + + +[ +![Picture](/blog/callserially-the-edt-invokeandblock-part-2/callserially-the-edt-invokeandblock-part-2-1.png) +](/img/blog/old_posts/callserially-the-edt-invokeandblock-part-2-large-2.png) + + + + + + + +The +[ +last time we talked about the EDT +](http://www.codenameone.com/blog/callserially-the-edt-invokeandblock-part-1) +we covered some of the basic ideas, such as call serially etc. We left out two major concepts that are somewhat more advanced. + +** +Invoke And Block +** + +When we write typical code in Java we like that code to be in sequence as such: + +doOperationA(); + +doOperationB(); + +doOperationC(); + +This works well normally but on the EDT it might be a problem, if one of the operations is slow it might slow the whole EDT (painting, event processing etc.). Normally we can just move operations into a separate thread e.g.: + +doOperationA(); + +new Thread() { + +public void run() { + +doOperationB(); + +} + +}).start(); + +doOperationC(); + +Unfortunately, this means that operation C will happen in parallel to operation C which might be a problem… E.g. instead of using operation names lets use a more “real world” example: + +updateUIToLoadingStatus(); + +readAndParseFile(); + +updateUIWithContentOfFile(); + +Notice that the first and last operations must be conducted on the EDT but the middle operation might be really slow! + +Since updateUIWithContentOfFile needs readAndParseFile to be before it doing the new thread won’t be enough. Our automatic approach is to do something like this: + +updateUIToLoadingStatus(); + +new Thread() { + +public void run() { + +readAndParseFile(); + +updateUIWithContentOfFile(); + +} + +}).start(); + +But updateUIWithContentOfFile should be executed on the EDT and not on a random thread. So the right way to do this would be something like this: + +updateUIToLoadingStatus(); + +new Thread() { + +public void run() { + +readAndParseFile(); + +Display.getInstance().callSerially(new Runnable() { + +public void run() { + +updateUIWithContentOfFile(); + +} + +}); + +} + +}).start(); + +This is perfectly legal and would work reasonably well, however it gets complicated as we add more and more features that need to be chained serially after all these are just 3 methods! + +Invoke and block solves this in a unique way you can get almost the exact same behavior by using this: + +updateUIToLoadingStatus(); + +Display.getInstance().invokeAndBlock(new Runnable() { + +public void run() { + +readAndParseFile(); + +} + +}); + +updateUIWithContentOfFile(); + +Invoke and block effectively blocks the current EDT in a legal way. It spawns a separate thread that runs the run() method and when that run method completes it goes back to the EDT. All events and EDT behavior still works while invokeAndBlock is running, this is because invokeAndBlock() keeps calling the main thread loop internally. + +Notice that this comes at a slight performance penalty and that nesting invokeAndBlocks (or over using them) isn’t recommended. However, they are very convenient when working with multiple threads/UI. + +** +Why Would I Invoke callSerially when I’m on the EDT already? +** + +We discussed callSerially in the previous post but one of the misunderstood topics is why would we ever want to invoke this method when we are still on the EDT. The original version of LWUIT used to throw an IllegalArgumentException if callSerially was invoked on the EDT since it seemed to make no sense. + +However, it does make some sense and we can explain that using an example. E.g. say we have a button that has quite a bit of functionality tied to its events e.g.: + +1\. A user added an action listener to show a Dialog. + +2\. A framework the user installed added some logging to the button. + +3\. The button repaints a release animation as its being released. + +However, this might cause a problem if the first event that we handle (the dialog) might cause an issue to the following events. E.g. a dialog will block the EDT (using invokeAndBlock), events will keep happening but since the event we are in “already happened” the button repaint and the framework logging won’t occur. This might also happen if we show a form which might trigger logic that relies on the current form still being present. + +One of the solutions to this problem is to just wrap the action listeners body with a callSerially. In this case the callSerially will postpone the event to the next cycle (loop) of the EDT and let the other events in the chain complete. Notice that you shouldn’t use this normally since it includes an overhead and complicates application flow, however when you run into issues in event processing I suggest trying this to see if its the cause. + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — March 2, 2015 at 7:34 pm ([permalink](https://www.codenameone.com/blog/callserially-the-edt-invokeandblock-part-2.html#comment-22285)) + +> Anonymous says: +> +> Hi, +> +> just want to inform that this page is containing typo mistake..which may lead to wrong assumption for new developers.. +> +> Its here: +> +> “Unfortunately, this means that operation C will happen in parallel to operation C which might be a problem…” +> +> I think one of the C should be B +> +> Please don’t take it wrong, just wanted to make CN1 cleanNshine. +> +> Thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcallserially-the-edt-invokeandblock-part-2.html) + + +### **Anonymous** — March 3, 2015 at 2:02 am ([permalink](https://www.codenameone.com/blog/callserially-the-edt-invokeandblock-part-2.html#comment-22353)) + +> Anonymous says: +> +> Thanks for the catch! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcallserially-the-edt-invokeandblock-part-2.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/camera-demo.md b/docs/website/content/blog/camera-demo.md new file mode 100644 index 0000000000..f9c282c160 --- /dev/null +++ b/docs/website/content/blog/camera-demo.md @@ -0,0 +1,50 @@ +--- +title: Camera Demo +slug: camera-demo +url: /blog/camera-demo/ +original_url: https://www.codenameone.com/blog/camera-demo.html +aliases: +- /blog/camera-demo.html +date: '2016-05-09' +author: Shai Almog +--- + +![Header Image](/blog/camera-demo/camera-demo-blog.png) + +With the 3.4 release we discussed the process of modernizing the demos and the first one we picked +for this task is the [camera demo](/demos-Camera.html) which is probably the easiest one of all the demos…​ +The demo is trivial and doesn’t really demonstrate anything other than capturing and showing an image captured +from the camera/retrieved from the gallery but this is where it gets interesting. It even works in the +JavaScript port so you can even [run this in the browser and it works as you’d expect](/demos/CameraDemo/)! + +Notice that since browsers don’t have anything quite like a “gallery” that feature won’t be very useful but capture +works really well. + +### The Source + +Check out the full source code for the demo in the +[github repository for the CameraDemo](https://github.com/codenameone/CameraDemo) notice that +[as we announced yesterday](/blog/java-8-switch-new-preferences-demo-structure.html) we are +moving the demos to separate repositories and will retire the monolithic +[codenameone-demos](https://github.com/codenameone/codenameone-demos) repository. This will allow +us to be more nimble and will also simplify the process of working with these demos. + +This demo will be integrated into the upcoming new project wizards in the various IDEs. This plays into the +move to Java 8 in the plugins which [we also announced yesterday](/blog/java-8-switch-new-preferences-demo-structure.html). + +### Moving Forward + +There are **many** demos in the [codenameone-demos](https://github.com/codenameone/codenameone-demos) +repository and some outside of it. Most of them are out of date and “abandoned” we’ll try to make this a weekly +segment of moving demos to the newer API’s and refining them. Some of these demos will take more effort (e.g Kitchen Sink) +but others should be simpler. + +Ideally all demos should be included in the IDE plugins and should be accessible by everyone easily. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/camerakit-low-level-camera-api.md b/docs/website/content/blog/camerakit-low-level-camera-api.md new file mode 100644 index 0000000000..0ed31930be --- /dev/null +++ b/docs/website/content/blog/camerakit-low-level-camera-api.md @@ -0,0 +1,75 @@ +--- +title: Camera Kit – Low Level Camera API +slug: camerakit-low-level-camera-api +url: /blog/camerakit-low-level-camera-api/ +original_url: https://www.codenameone.com/blog/camerakit-low-level-camera-api.html +aliases: +- /blog/camerakit-low-level-camera-api.html +date: '2018-03-28' +author: Shai Almog +--- + +![Header Image](/blog/camerakit-low-level-camera-api/camera-kit-banner.jpg) + +When we introduced support for z-ordering of peer components in Codename One we listed two major targets. The first was already available: Map. The second was still pending: Camera. +Our current `Capture` API is very high level and removes a lot of the control from the developer. In order to give developers a high level of control we created [Camera Kit](https://github.com/codenameone/CameraKitCodenameOne/tree/master). + +[Camera Kit](https://github.com/codenameone/CameraKitCodenameOne/tree/master) is based on a native [Android Camera Kit project](https://github.com/CameraKit/camerakit-android/) whose API we used to implement the Android port and for inspiration. This new API works on Android & iOS at this time. It allows you to grab photos/videos & view the camera preview like you would any other media. + +You can overlay your Codename One widgets on top of the camera view as you can see in the project sample and screenshot. + +This effectively makes a lot of previously impossible use cases possible. E.g. grabbing a photo after a given interval, grabbing a video for a fixed number of seconds. Placing a UI element on top of the camera view etc. + +One of the really cool things about this is that it’s entirely in a cn1lib. That means you can grok the code without understanding Codename One. You can fix issues and add functionality without knowing too much. + +As a sidenote the reason we picked up this task is because an enterprise customer asked for this…​ If you can afford an enterprise account we really appreciate it and everyone gets the benefit of the new functionality! +So if the company you work for can purchase an enterprise account this can help everyone who uses Codename One. + +### Status & Future + +Right now only a part of the functionality is implemented on iOS with some nuances still missing. On Android we get errors due to a bug in the native Android Camera Kit library. Since the native library is heading for a 1.0 version this should be resolved when we update to that. + +I would love to see ports of this to other Codename One platforms and the simulator. We’ll take a look at these as we move forward based on user demand. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Amuche Chimezie** — March 29, 2018 at 3:45 pm ([permalink](https://www.codenameone.com/blog/camerakit-low-level-camera-api.html#comment-23779)) + +> Amuche Chimezie says: +> +> Awesome!! Finally.. Thank you Shai +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcamerakit-low-level-camera-api.html) + + +### **thunderkilll** — April 27, 2018 at 5:47 am ([permalink](https://www.codenameone.com/blog/camerakit-low-level-camera-api.html#comment-23805)) + +> thunderkilll says: +> +> please i have question how can i change the file Path trajectory String filePath = Capture.capturePhoto(); +> and instead the filePath = “http://localhost/images/”+imageName ; +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcamerakit-low-level-camera-api.html) + + +### **Shai Almog** — April 28, 2018 at 5:32 am ([permalink](https://www.codenameone.com/blog/camerakit-low-level-camera-api.html#comment-23734)) + +> Shai Almog says: +> +> That’s a URL not a file path. Your app needs to save the file to a path you “own” which is the file system app home directory. Can you clarify what you are trying to do? +> +> Notice that you can’t copy a file everywhere in a mobile OS as devices isolate the apps from one another to prevent security exploits. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcamerakit-low-level-camera-api.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/camerakit-rewrite.md b/docs/website/content/blog/camerakit-rewrite.md new file mode 100644 index 0000000000..23f2603e31 --- /dev/null +++ b/docs/website/content/blog/camerakit-rewrite.md @@ -0,0 +1,65 @@ +--- +title: Camera Kit Rewrite +slug: camerakit-rewrite +url: /blog/camerakit-rewrite/ +original_url: https://www.codenameone.com/blog/camerakit-rewrite.html +aliases: +- /blog/camerakit-rewrite.html +date: '2019-04-29' +author: Shai Almog +--- + +![Header Image](/blog/camerakit-rewrite/camera-kit-banner.jpg) + +The native low level camera API on Android is a disaster. It’s often cited as one of the worst API’s on Android. To make matters worse there are two separate API’s `Camera` and `Camera2` (yes really). You need to use `Camera2` where it’s available but that means no support for older devices. To solve this we picked the Android Camera Kit library when we started building our low level camera support. This proved to be a mistake. + +Camera Kit was supposed to reach 1.0 status for about a year now. It constantly moved the goal posts and eventually moved the entire implementation to Android X which meant breaking compatibility on a large scale with existing code. After waiting endlessly for 1.0 we eventually tried to move to the latest beta but this proved unworkable due to the usage of Android X. So we decided to solve this by moving to [Golden Eye](https://github.com/infinum/Android-GoldenEye). It’s a far simpler solution and as a result a stabler one. + +__ | As I write this it looks like Camera Kit is moving towards 1.0 but it’s still unclear +---|--- + +We still kept the name for the cn1lib which might breed some confusion so we’re open to suggestions here and might update it in the future. + +As part of this overhaul we the library now supports the JavaScript port. It doesn’t support all the features but you should be able to get low level camera access in your web apps as well. + +The nice thing is that the API is mostly unchanged. It can still be used with roughly the same API as we had before: +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Thomas McNeill** — May 1, 2019 at 12:20 am ([permalink](https://www.codenameone.com/blog/camerakit-rewrite.html#comment-23550)) + +> Thomas McNeill says: +> +> Awesome. Call it CameraKit2. I was trying to use it in the middle of the transition and was having issues. Glad it’s out now. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcamerakit-rewrite.html) + + +### **Durank** — May 3, 2019 at 5:03 pm ([permalink](https://www.codenameone.com/blog/camerakit-rewrite.html#comment-24028)) + +> Durank says: +> +> how can I launch camera in landscape with this api? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcamerakit-rewrite.html) + + +### **Shai Almog** — May 4, 2019 at 4:43 am ([permalink](https://www.codenameone.com/blog/camerakit-rewrite.html#comment-24114)) + +> Shai Almog says: +> +> Force landscape in the app using setPortait (this will work on Android only) then embed the camera in the form. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcamerakit-rewrite.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/can-execute-hint.md b/docs/website/content/blog/can-execute-hint.md new file mode 100644 index 0000000000..641246f0d0 --- /dev/null +++ b/docs/website/content/blog/can-execute-hint.md @@ -0,0 +1,47 @@ +--- +title: Can Execute Hint +slug: can-execute-hint +url: /blog/can-execute-hint/ +original_url: https://www.codenameone.com/blog/can-execute-hint.html +aliases: +- /blog/can-execute-hint.html +date: '2017-01-24' +author: Shai Almog +--- + +![Header Image](/blog/can-execute-hint/new-features-1.jpg) + +`Display.canExecute(url)` provides us with a generic tool to test the availability of a feature before executing a command. This is very useful for inter-app communications and allows us to achieve various things such as launching Google Map instead of Apple Maps on iOS. + +Lets say I want to navigate using Google Maps if it’s installed in iOS but if not I’ll settle for Apple Maps I can do something like this: + + + String url = "comgooglemaps://?q=" + Util.encodeUrl(address); + Boolean b = Display.getInstance().canExecute(url); + if(b != null && b.booleanValue()) { + Display.getInstance().execute(url); + } else { + // google maps is probably not installed + Display.getInstance().openNativeNavigationApp(address); + } + +This should work and would have worked but might not have…​ + +The reason this might have failed in recent iOS & xcode versions is because Apple changed the behavior of the underlying API used by `canExecute` to always return `false`. The workaround is to add the prefix of the URL into a list within the plist file. We have a build hint for that which accepts a comma separated list: + + + ios.applicationQueriesSchemes=comgooglemaps + +If there are additional entries you can separate them with a comma. You can use up to 50 URL prefixes. + +The reason for this requirement isn’t 100% clear but it’s assumed that some apps used this feature to query the installed apps on the device thus violating users privacy in a subtle way. + +Thanks to the recent [build hint automation](/blog/automatic-build-hints-configuration.html) we can detect cases where you use the `canExecute` API and automatically setup the build hint correctly. Obviously, this won’t work for dynamic values that change on the device but should work for standard prefixes. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/can-execute.md b/docs/website/content/blog/can-execute.md new file mode 100644 index 0000000000..3e776da1a4 --- /dev/null +++ b/docs/website/content/blog/can-execute.md @@ -0,0 +1,101 @@ +--- +title: Can Execute +slug: can-execute +url: /blog/can-execute/ +original_url: https://www.codenameone.com/blog/can-execute.html +aliases: +- /blog/can-execute.html +date: '2014-07-13' +author: Shai Almog +--- + +![Header Image](/blog/can-execute/can-execute-1.png) + + + + + +![Picture](/blog/can-execute/can-execute-1.png) + + + + +Runtime.exec is pretty familiar to Java developers (and the process builder in later versions), however for mobile applications we usually don’t have access to an executable. The solution is to invoke a URL which is bound to a particular application, this works rather well assuming the application is installed and you can activate quite a few things e.g. this is a partial list of +[ +URL’s that work on iOS +](http://wiki.akosma.com/IPhone_URL_Schemes) +. (notice that a lot of these are redundant since we have builtin portable functionality to address those features). + + +Normally on iOS you would do something like + +canOpenURL followed by openURL assuming the can message returned true. However, Android et al doesn’t have anything quite like that. To enable this at least for iOS if not elsewhere we added a Display.canExecute() method to go with the Display.execute() method. However, canExecute returns a Boolean instead of a boolean which allows us to support 3 result states: + + +1\. Boolean.TRUE – the URL can be executed. + + + + +2\. Boolean.FALSE – the URL can be executed. + + +3\. null – we have no idea whether this will work on this platform. + + + + +We’ve added an experimental BigInteger/BigDecimal implementation to the util package. This is a very basic implementation lifted from the Bouncy Castle work, but these are big omissions in our current code which should allow more business/scientific code to be ported. + + + + +We also have an experimental (deprecated) port of the MiG layout in place. We ported it due to a long standing RFE but it doesn’t seem to be working as expected, its hard to tell the source of the problem and we aren’t sure if we want to go in that direction. If this is something that is interesting to you let us know and also check out if you can spot our mistakes in the port. + + + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — September 18, 2014 at 5:18 am ([permalink](https://www.codenameone.com/blog/can-execute.html#comment-21978)) + +> Anonymous says: +> +> Is Can execute also usable on Android? If so, is there somewhere a list of Android specific urls? +> +> Wim +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcan-execute.html) + + +### **Anonymous** — September 18, 2014 at 3:27 pm ([permalink](https://www.codenameone.com/blog/can-execute.html#comment-22030)) + +> Anonymous says: +> +> No, Android doesn’t really have anything quite like that. It has something potentially more powerful: intents. Which you can invoke via the execute call and also receive a response from said intent. +> +> Since everything in Android is an Intent there isn’t so much a list of them as much as just googling the intent for whatever you want. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcan-execute.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/cats-in-toolbars.md b/docs/website/content/blog/cats-in-toolbars.md new file mode 100644 index 0000000000..fc81ac62f7 --- /dev/null +++ b/docs/website/content/blog/cats-in-toolbars.md @@ -0,0 +1,180 @@ +--- +title: Cats in Toolbars +slug: cats-in-toolbars +url: /blog/cats-in-toolbars/ +original_url: https://www.codenameone.com/blog/cats-in-toolbars.html +aliases: +- /blog/cats-in-toolbars.html +date: '2015-01-04' +author: Shai Almog +--- + +![Header Image](/blog/cats-in-toolbars/cats-in-toolbars-1.png) + + + + + +![Picture](/blog/cats-in-toolbars/cats-in-toolbars-1.png) + + + + + + + + + + +Chen spent some time working on some Toolbar effects such as the rich title areas made popular by social network apps such as G+ & Twitter. The new Flickr demo in SVN now shows a really cool ability to fold the title bar as we scroll down and expand it when we scroll up. It also shows an image based title area that can fade out of view during scrolling. Check out the video below to get a taste of the possibilities. + +We hope to make an update to the plugin this week or the next, it will include the new Toolbar functionality and other fixes. + +On the new VM front we closed multiple open bugs in the new VM and are considering it a solid beta. We are starting to look into new features that we can enable thanks to its architecture. + + + + + + + + +* * * + + + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — January 5, 2015 at 7:16 pm ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-22190)) + +> Anonymous says: +> +> That’s an interesting demo. I notice that there is no back behaviour (i.e. on Android the hardware back key exits the application, irrespective of which form you are on). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Anonymous** — January 6, 2015 at 7:45 am ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-22226)) + +> Anonymous says: +> +> Is it possible to mix SideMenuBar with native android action bar in the same app now? For example one form i might want to use the SideMenuBar, but the next form, I might want to use the android action bar? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Anonymous** — January 7, 2015 at 5:08 am ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-22062)) + +> Anonymous says: +> +> Yes, should be possible with the Toolbar +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Anonymous** — January 7, 2015 at 6:41 am ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-22199)) + +> Anonymous says: +> +> Thanks Chen, very good work! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Anonymous** — January 7, 2015 at 8:43 am ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-21606)) + +> Anonymous says: +> +> What a great feature. Will this be available on iOS too? And is it possible to zoom in the cat image when you tensileDrag the container down? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Anonymous** — January 7, 2015 at 6:17 pm ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-21951)) + +> Anonymous says: +> +> This feature is available to all supported platforms. +> +> Zoom in should be possible, I suggest you to check out the new Flickr Demo from the project svn and have a look at the code. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Anonymous** — January 8, 2015 at 5:52 am ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-22089)) + +> Anonymous says: +> +> I hear Windows Port in general is still flimsy, not sure what that status is on that but I do notice more Windows Phone support in my country. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Anonymous** — January 19, 2015 at 11:44 pm ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-24186)) + +> Anonymous says: +> +> This toolbar is available now ?, I’m downloaded the netbeans plugin updated in 13-01-2015 and Toolbar class and form.setToolbar not exists… Why ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Anonymous** — January 20, 2015 at 4:14 am ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-22213)) + +> Anonymous says: +> +> Right click the project. Click “Preference” select the Codename One section and click “Update Client Libraries”. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Anonymous** — January 24, 2015 at 11:19 am ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-22157)) + +> Anonymous says: +> +> Im very interested in this functionality. +> +> Is this being done via the gui? Or is this something that is hardcoded? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Anonymous** — January 25, 2015 at 6:16 am ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-24194)) + +> Anonymous says: +> +> This is handcoded although you could use a Toolbar in a GUI builder application as well but you would have to handcode that portion in the before form call. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Sanne Graaf** — October 15, 2015 at 12:13 pm ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-22277)) + +> Sanne Graaf says: +> +> Where can I find the sourcecode of this exampe? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + + +### **Shai Almog** — October 16, 2015 at 12:54 pm ([permalink](https://www.codenameone.com/blog/cats-in-toolbars.html#comment-22085)) + +> Shai Almog says: +> +> Here: [https://github.com/codename…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcats-in-toolbars.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/certificate-verification-avoid-pinning-vulnerability.md b/docs/website/content/blog/certificate-verification-avoid-pinning-vulnerability.md new file mode 100644 index 0000000000..1fb188000f --- /dev/null +++ b/docs/website/content/blog/certificate-verification-avoid-pinning-vulnerability.md @@ -0,0 +1,274 @@ +--- +title: Certificate Verification, Avoid SSL Pinning Vulnerability +slug: certificate-verification-avoid-pinning-vulnerability +url: /blog/certificate-verification-avoid-pinning-vulnerability/ +original_url: https://www.codenameone.com/blog/certificate-verification-avoid-pinning-vulnerability.html +aliases: +- /blog/certificate-verification-avoid-pinning-vulnerability.html +date: '2017-01-10' +author: Shai Almog +--- + +![Header Image](/blog/certificate-verification-avoid-pinning-vulnerability/security.jpg) + +Certificate pinning is a security measure designed to thwart potentially dangerous and complex attacks. Since those sort of attacks are pretty hard to execute it’s a security measure that is probably unnecessary for most developers. However, if you are building an application for a very sensitive industry (e.g. Government, Banking etc.) you might be required to include this defensive measure. + +When we connect to an HTTPS server our client checks the certificate on the server. If the certificate was issued by a trusted certificate authority then the connection goes thru otherwise it fails. Let’s imagine a case where I’m sitting in a coffee shop connected to the local wifi, I try to connect to gmail to check my email. Since I use HTTPS to Google I trust my connection is secure. + +What if the coffee shop was hacked and the router is listening in on everything? + +So HTTPS is encrypted and the way encryption works is thru the certificate. The server sends me a certificate and we can use that to send encrypted data to it. + +What if the router grabs the servers certificate and communicates with Google in my name? + +This won’t work since the data we send to the server is encrypted with the certificate from the server. + +So what if the router sends its own “fake certificate”? + +That won’t work either. All certificates are signed by a “certificate authority” indicating that a google.com certificate is valid. + +What if I was able to get my fake certificate authorized by a real certificate authority? + +That’s a problem! + +It’s obviously hard to do but if someone was able to do this he could execute a “man in the middle” attack as described above. People were able to fool certificate authorities in the past and gain fake certificates using various methods so this is possible and probably doable for any government level attacker. + +### Certificate Pinning + +This is the attack certificate pinning (or SSL pinning) aims to prevent. We code into our app the “fingerprint” of the certificate that is “good” and thus prevent the app from working when the certificate is “fake”. This might break the app if we replace the certificate at some point but that might be reasonable in such a case. + +To do this we introduced a [new cn1lib](https://github.com/codenameone/SSLCertificateFingerprint/). that fetches the certificate fingerprint from the server, we can just check this fingerprint against a list of “authorized” keys to decide whether it is valid. You can install the `SSLCertificateFingerprint` from the extensions section in Codename One Settings and use something like this to verify your server: + + + if(CheckCert.isCertCheckingSupported()) { + String f = CheckCert.getFingerprint(myHttpsURL); + if(validKeysList.contains(f)) { + // OK it's a good certificate proceed + } else { + if(Dialog.show("Security Warning", "WARNING: it is possible your commmunications are being tampered! We suggest quitting the app at once!", "Quit", "Continue")) { + Display.getInstance().exitApplication(); + } + } + } else { + // certificate fingerprint checking isn't supported on this platform... It's your decision whether to proceed or not + } + +Notice that once connection is established you don’t need to verify again for the current application run. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Eric Kimotho** — January 18, 2021 at 7:09 pm ([permalink](https://www.codenameone.com/blog/certificate-verification-avoid-pinning-vulnerability.html#comment-24379)) + +> Eric Kimotho says: +> +> This is great. +> +> How do we get “validKeysList” required in this line +> +> if(validKeysList.contains(f)) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcertificate-verification-avoid-pinning-vulnerability.html) + + +### **Shai Almog** — January 19, 2021 at 2:46 am ([permalink](https://www.codenameone.com/blog/certificate-verification-avoid-pinning-vulnerability.html#comment-24380)) + +> Shai Almog says: +> +> This article is somewhat out of date by now. We have a builtin approach that works better. See: +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcertificate-verification-avoid-pinning-vulnerability.html) + + +### **Eric Kimotho** — January 19, 2021 at 8:03 pm ([permalink](https://www.codenameone.com/blog/certificate-verification-avoid-pinning-vulnerability.html#comment-24381)) + +> Eric Kimotho says: +> +> Thank you. I tried to follow link above and came up snippet below. But length of SSLCertificate Array is 0 for all https url i tried. Please note i am using synchronous version of ConnectionRequest to be able to update UI incase network error. Please assist with correct implementation +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcertificate-verification-avoid-pinning-vulnerability.html) + + +### **Eric Kimotho** — January 19, 2021 at 8:05 pm ([permalink](https://www.codenameone.com/blog/certificate-verification-avoid-pinning-vulnerability.html#comment-24382)) + +> Eric Kimotho says: +> +> private void certPinning() { +> +> ConnectionRequest request = new ConnectionRequest(); +> request.setUrl(myHttpsUrl); +> +> request.setCheckSSLCertificates(true); +> +> switch (Display.getInstance().getPlatformName()) { +> case “and”: +> case “ios”: +> try { +> if (request.canGetSSLCertificates() +> && getSSLCertArray(request).length > 0) { +> +> new SignIn().show(); +> } else { +> showWarningAlert(“Connection Alert”, +> “Secure Connection is tampered, quit app now”); +> } +> } catch (IOException e) { +> Log.p(“Exception ” + e.getMessage()); +> } +> break; +> +> case “win”: +> new SignIn().show(); +> break; +> } +> +> } +> +> private SSLCertificate[] getSSLCertArray(ConnectionRequest request) +> throws IOException { +> Log.p(\nCert Length ” + request.getSSLCertificates().length); +> return request.getSSLCertificates(); +> } +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcertificate-verification-avoid-pinning-vulnerability.html) + + +### **Shai Almog** — January 20, 2021 at 3:25 am ([permalink](https://www.codenameone.com/blog/certificate-verification-avoid-pinning-vulnerability.html#comment-24385)) + +> Shai Almog says: +> +> This is before the call. I specifically pointed at checkSSLCertificates which is a callback that will be invoked when the request data arrives. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcertificate-verification-avoid-pinning-vulnerability.html) + + +### **Eric Kimotho** — January 20, 2021 at 6:05 pm ([permalink](https://www.codenameone.com/blog/certificate-verification-avoid-pinning-vulnerability.html#comment-24386)) + +> Eric Kimotho says: +> +> At least using below implementations i can get certificate length as 2, Please Confirm if these implementations are okay +> +> //Synchronous Implementation +> +> private void certPinning() { +> +> ConnectionRequest request = new ConnectionRequest(); +> +> request.setUrl(myHttpsUrl); +> request.setHttpMethod(“POST”); +> request.setTimeout(15000); +> request.setReadTimeout(20000); +> request.addArgument(“dataTag”, “request data”); +> request.setFailSilently(true); +> request.setCheckSSLCertificates(true); +> +> NetworkManager.getInstance().addToQueueAndWait(request); +> +> switch (request.getResponseCode()) { +> +> case 0: +> case 404: +> //Connection error +> break; +> +> case 200: +> byte[] result = request.getResponseData(); +> String resp = new String(result); +> break; +> } +> +> switch (Display.getInstance().getPlatformName()) { +> case “and”: +> case “ios”: +> try { +> +> if (request.canGetSSLCertificates() +> && getSSLCertArray(request).length > 0) { +> //Continue +> } else { +> showWarningAlert(“Connection Alert”, +> “Secure Connection is tampered, quit app now”); +> } +> } catch (IOException e) { +> +> } +> break; +> case “win”: +> //Continue +> break; +> } +> } +> +> private SSLCertificate[] getSSLCertArray(ConnectionRequest request) +> throws IOException { +> Log.p(\nCert Length ” + request.getSSLCertificates().length); +> return request.getSSLCertificates(); +> } +> ============================================== +> //Asynchronous Implementation +> //Seems checkSSLCertificates function requires Asynchronous version of ConnectionRequest +> +> private void certPinning() { +> String resp; +> ConnectionRequest request = new ConnectionRequest(){ +> +> @Override +> protected void checkSSLCertificates(SSLCertificate[] certificates) { +> +> Log.p(“Cert Len ” + certificates.length); +> +> switch (Display.getInstance().getPlatformName()) { +> case “and”: +> case “ios”: +> if (certificates.length == 0) { +> +> Log.p(“Secure Connection is tampered, quit app now”); +> } else { +> //Continue +> } +> break; +> +> case “win”: +> //Continue +> break; +> } +> +> } +> } +> +> @Override +> protected void readResponse(InputStream input) throws IOException { +> result = Result.fromContent(input, Result.JSON); +> resp = result.getAsString(“root”); +> } +> +> @Override +> protected void postResponse() { +> Log.p(resp); +> } +> +> request.setUrl(myHttpsUrl); +> request.setHttpMethod(“POST”); +> request.setTimeout(15000); +> request.setReadTimeout(20000); +> request.addArgument(“dataTag”, “request data”); +> request.setFailSilently(true); +> request.setCheckSSLCertificates(true); +> +> NetworkManager.getInstance().addToQueue(request); +> NetworkManager.getInstance().addErrorListener((e) -> e.consume()); +> +> } +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcertificate-verification-avoid-pinning-vulnerability.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/changes-2017-milestones-dst-hotfix.md b/docs/website/content/blog/changes-2017-milestones-dst-hotfix.md new file mode 100644 index 0000000000..aaa08dadb4 --- /dev/null +++ b/docs/website/content/blog/changes-2017-milestones-dst-hotfix.md @@ -0,0 +1,61 @@ +--- +title: Changes to 2017 Milestones and DST Hotfix +slug: changes-2017-milestones-dst-hotfix +url: /blog/changes-2017-milestones-dst-hotfix/ +original_url: https://www.codenameone.com/blog/changes-2017-milestones-dst-hotfix.html +aliases: +- /blog/changes-2017-milestones-dst-hotfix.html +date: '2017-03-20' +author: Shai Almog +--- + +![Header Image](/blog/changes-2017-milestones-dst-hotfix/generic-java-2.jpg) + +We released an important fix for an issue with daylight saving in north America (DST), if you are experiencing weird issues only on iOS that could be attributed to time problems then please send a new build to see if the fix works correctly. Our iOS VM code made some assumptions about DST which were apparently false. We chose to release it outside of our regular update schedule due to the significance of this issue. + +### Release Schedule + +Due to the tight schedule of the bootcamp we’re postponing some of the previously announced to 2017 milestones so we won’t need to split our focus. The bootcamp ends on May 1st and might require some more effort after it completes and we don’t want to draw the attention from the release. Since our set of open issues is ridiculously large there is just no other way. + +The [3.7 milestone](https://github.com/codenameone/CodenameOne/milestone/9) was planned for May 9th. We’ve decided to postpone it to June 27th (a date I just randomly picked with no reason at all). + +The [3.8 milestone](https://github.com/codenameone/CodenameOne/milestone/10) was planned for October 4th, I’m not a fan of December releases and even November is problematic but I don’t want to slip the release into 2018 so we will go for November 14th as the new release date. + +### Our Activity During the Bootcamp + +During the weeks of the bootcamp the blog won’t post updates unless there is something urgent that we need to communicate. We won’t do the standard Friday release either during those dates. Since the bootcamp is split in the middle we will have regular activity during the off week of the bootcamp. + +Support which I usually handle will be split between employees with Steve taking most of the public support effort and the pro/enterprise support aliases. Things should function as usual for the most par however if you are one of the people who emails me directly instead of the support alias, or one of the people who doesn’t mention his pro/enterprise account in his email you might not get an answer. + +So please make sure to include that information in support queries (in general not just now). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chris** — March 22, 2017 at 5:50 pm ([permalink](https://www.codenameone.com/blog/changes-2017-milestones-dst-hotfix.html#comment-23212)) + +> Chris says: +> +> New Build still I do see there is a 1 hour delay for DST. On simulator, it was working properly but not on iOS. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fchanges-2017-milestones-dst-hotfix.html) + + +### **Shai Almog** — March 23, 2017 at 5:55 am ([permalink](https://www.codenameone.com/blog/changes-2017-milestones-dst-hotfix.html#comment-23221)) + +> Shai Almog says: +> +> We had a bug in the first fix (worked on the simulator but failed on devices) we’ve since patched it and got confirmation it works. Can you test again? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fchanges-2017-milestones-dst-hotfix.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/changes-stacks.md b/docs/website/content/blog/changes-stacks.md new file mode 100644 index 0000000000..c0dab4b7fa --- /dev/null +++ b/docs/website/content/blog/changes-stacks.md @@ -0,0 +1,45 @@ +--- +title: Changes & Stacks +slug: changes-stacks +url: /blog/changes-stacks/ +original_url: https://www.codenameone.com/blog/changes-stacks.html +aliases: +- /blog/changes-stacks.html +date: '2014-05-10' +author: Shai Almog +--- + +![Header Image](/blog/changes-stacks/changes-stacks-1.png) + + + + + +![Picture](/blog/changes-stacks/changes-stacks-1.png) + + + + +One of the great features we’ve added to the new iOS VM is the ability to get proper stack traces without a performance penalty. This is actually pretty easy to implement in a performant way, every entry to a method just registers an integer number representing the method name and class name and every time we reach a line number in the source file we update the current line number. When throwing the exception we just assemble all of that data to produce the exception and the cost in terms of RAM/CPU is very low. + +We were hoping to expose the build argument for the new VM by now but right now builds are slow for some unclear reason… We have significantly less code in the new VM and its simpler code since it doesn’t include a lot of functionality that was necessary for the full Harmony API. But it builds slower and we are a bit stumped by that… + +We are busy catching up to the many issues and RFE’s opened by pro/enterprise users during the past few weeks as we were working on the new VM. Some features/fixes of interest include the JSONParser which now has a special mode called setUseLongs(). This mode uses long objects for round values rather than doubles. So a numeric value might be a long or it might be a double. + +By default the JSON parser always produces Doubles, the reason behind that is that we are missing support for the java.lang.Number class which would have been really useful for this case. Without that class its difficult to write a generic parser so we chose to go only with doubles. However, for larger numbers this is a problem which is why we now also offer the option to generate longs. + +In addition we made maps within the JSON (key/value pairs) use LinkedHashMap rather than HashMap, this preserves their order from within the JSON after parsing which is important for some use cases. + +We added an isDesktop method to indicate if we are currently within a Desktop application (similar to isTablet()) and a canDial() method, both of whihc are part of Display. This is important since dialing from Tablets or Desktop machines will naturally fail so you might not want to show a button in the UI that will lead to a dial() invocation. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/charts-demo-revisited.md b/docs/website/content/blog/charts-demo-revisited.md new file mode 100644 index 0000000000..dee62480bc --- /dev/null +++ b/docs/website/content/blog/charts-demo-revisited.md @@ -0,0 +1,61 @@ +--- +title: Charts Demo Revisited +slug: charts-demo-revisited +url: /blog/charts-demo-revisited/ +original_url: https://www.codenameone.com/blog/charts-demo-revisited.html +aliases: +- /blog/charts-demo-revisited.html +date: '2016-06-29' +author: Shai Almog +--- + +![Header Image](/blog/charts-demo-revisited/charts-demo.jpg) + +The charts demo is one of the most elaborate/messy demos we have as it was derived/ported from an +[aChartEngine](http://www.achartengine.org/) demo. Since the +[Codename One charts](https://www.codenameone.com/javadoc/com/codename1/charts/package-summary.html) +are themselves a derivative of aChartEngine this makes a lot of sense but the demo is a bit big and hard to +follow. + +However, it does show off a lot of the chart types that can be created using the charts package. As such it is a +very valuable demo…​ + +We’d love to modernize it more but time constraints make this impractical, for now we did the following: + + * Added a new tablet mode which makes the demo look completely different on the tablet using it’s screen dimensions +properly + + * Streamlined the colors/fonts – a lot of the charts were inconsistent and had really tiny/unreadable fonts + + * Switched to Toolbar – while we don’t make extensive use of this API in the demo it’s now the base API + + * Migrated the code to Java 8 syntax – we didn’t do it for every case where it could be used but the project +is now a Java 8 project + + * Added pinch/pan to all the charts – this uses the builtin API in the `ChartComponent` class + + * Added some experimental features (e.g. chart editing) which are turned off by default at the moment. These were +half baked and getting this to work across all the charts and with all the features would have been challenging + +**Check out a live preview of the demo on the right here thanks to our JavaScript port!** + +The preview works in the mobile phone mode, to see this running in the tablet mode just open +[this link](/demos/ChartsDemo/) and it will run in desktop/tablet mode. + +Things like pinch to zoom don’t work in the JavaScript port for some reason but they should work reasonably +well on the device. + +### The Source + +Check out the full source code for the demo in the +[github repository for the Charts demo](https://github.com/codenameone/Charts). + +This demo will be integrated into the upcoming new project wizards in the various IDEs. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/chrome-demo.md b/docs/website/content/blog/chrome-demo.md new file mode 100644 index 0000000000..c05cc11d60 --- /dev/null +++ b/docs/website/content/blog/chrome-demo.md @@ -0,0 +1,98 @@ +--- +title: Chrome Demo +slug: chrome-demo +url: /blog/chrome-demo/ +original_url: https://www.codenameone.com/blog/chrome-demo.html +aliases: +- /blog/chrome-demo.html +date: '2016-05-15' +author: Shai Almog +--- + +![Header Image](/blog/chrome-demo/chrome-demo.png) + +This week we chose to modernize the very outdated [Chrome Demo](/demos-Chrome.html). This demo +is one of our early demos developed during the iOS 4.x era. We licensed it’s original design from +[app design vault](http://www.appdesignvault.com/shop/chrome/) and created a Codename One version +of that original template. While the guys in app design vault modernized most of their templates to iOS 7 +flat design they didn’t do this for the Chrome demo. + +**Check out a live preview of the demo on the right here thanks to our JavaScript port!** + +We were a bit conflicted on whether this demo should be kept or discarded but we eventually decided to keep +it due to two major reasons: + + * The calculator portion of the demo is pretty cool + + * It customizes the calendar widget and makes it look pretty decent. + +### GUI Builder + +The Chrome demo was built using the GUI builder which we are now de-emphasizing in favor of the upcoming +new GUI builder. We converted the demo to use the new GUI builder code using the +[migration wizard](/blog/terse-syntax-migration-wizard-more.html) and this was a relatively smooth process +although we needed to do some work to cleanup the old state machine and event handling. Since the demo +didn’t have much navigation logic and is relatively small the process was pretty easy. + +### Design + +We removed a lot of the brushed metal effects in the design to make the app feel more modern, we updated the +fonts and replaced some of the icons with icon fonts. Specifically we used the builtin material design icons. + +This improved the design considerably but this is probably not our most refined demo. + +### The Source + +Check out the full source code for the demo in the +[github repository for the Chrome demo](https://github.com/codenameone/Chrome). + +This demo will be integrated into the upcoming new project wizards in the various IDEs. + +### Up Next + +So far so good for our demo walkthru but these are still relatively simple demos, we hope to start tackling the +more challenging and interesting demos that might be harder to adapt to newer conventions. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Ross Taylor** — May 17, 2016 at 4:35 pm ([permalink](https://www.codenameone.com/blog/chrome-demo.html#comment-22782)) + +> Ross Taylor says: +> +> Nice demo! However I wonder why it takes a while to load the app (around 15 – 30 seconds) is it line speed (I have 10Mbps), browser (Firefox v46) or your Javascript Port itself? What happens if the app is large around 23MB? Will it affect the load time in the browser? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fchrome-demo.html) + + +### **Shai Almog** — May 18, 2016 at 3:54 am ([permalink](https://www.codenameone.com/blog/chrome-demo.html#comment-22702)) + +> Shai Almog says: +> +> The demo runs locally so once it’s downloaded everything is here. There are several large files it needs to download in advance e.g. the theme is 800kb but the biggest problem is [http://codenameone.com/demo…]() which is 1.7mb. +> +> I think our current server doesn’t gzip the JavaScript file so that might be a problem. +> +> 1.7MB is pretty small for what is effectively a full application with the JVM included but it does have a startup time overhead. This isn’t huge when compared to the many existing sites on the internet today in terms of data volume, but unlike those sites we need the whole thing to download before we can startup the VM. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fchrome-demo.html) + + +### **Shai Almog** — May 18, 2016 at 5:09 am ([permalink](https://www.codenameone.com/blog/chrome-demo.html#comment-22669)) + +> Shai Almog says: +> +> Actually looking at this again it seems our CDN does gzip the file so it’s really 300kb or so which is pretty impressive… Looking at the firefox logs I think this might be the time taking to load the javascript and the resource files which are pretty large for this application (around 1.2mb). I think a lot of the resources can be optimized to reduce startup time further. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fchrome-demo.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/clarifying-our-support.md b/docs/website/content/blog/clarifying-our-support.md new file mode 100644 index 0000000000..991a743606 --- /dev/null +++ b/docs/website/content/blog/clarifying-our-support.md @@ -0,0 +1,270 @@ +--- +title: Clarifying our Support +slug: clarifying-our-support +url: /blog/clarifying-our-support/ +original_url: https://www.codenameone.com/blog/clarifying-our-support.html +aliases: +- /blog/clarifying-our-support.html +date: '2016-05-03' +author: Shai Almog +--- + +![Header Image](/blog/clarifying-our-support/support-channels.jpg) + +For years we treated support with a “we’ll meet our developers where they are” attitude which is problematic +now that we have more than 6 free support channels! + +Notice that we didn’t include the email/phone support for pro/enterprise users in the list of 6 channels…​ + +We try to respond to every query within 24 hours in stack overflow and the discussion group: + + * [StackOverflow](http://stackoverflow.com/tags/codenameone) – please try asking any technical question here. +We know it’s sometimes challenging but the payout is great as the site is very searchable and provides a +treasure trove of Codename One information thanks to your questions! + + * [Github issue tracker](/blog/issue-submission-guideline.html) – If you are new to Codename One I would +suggest asking in the [discussion group](/discussion-forum.html) first and reading the blog post linked here + + * This blog – the comments section in the blog posts and even in the [developer guide](/manual/) is a +good place for questions relevant to a specific entry + + * [Discussion Group](/discussion-forum.html) – Our venerable Google group isn’t an ideal tool but it works as +a last resort. We prefer stack overflow but we still provide support there + + * Intercom – You can chat with our moderately technical support team live by clicking the chat button at the bottom +right side of the screen. If you have problems with the site, your account or similar issues/requests please send +them thru there. Notice that it’s not a good place for technical questions about programming e.g. “how +do I do X” in Codename One + + * [Facebook](http://facebook.com/CodenameOne), [Twitter](http://twitter.com/Codename_One) & +[LinkedIn](https://www.linkedin.com/company/codename-one) – While you can ask some things in these channels +the structure of the response makes it very hard to answer. We occasionally get questions on twitter and fitting the +answer into a tweet is impractical. LinkedIn recently updated the group interface and +[our group on LinkedIn](https://www.linkedin.com/groups/4313605) might become more active but currently +it doesn’t see much interaction + +__ | Often Googling things like Codename One followed by your question would produce answers, you can +also search stack overflows `codenameone` tag by prefixing your query with the tag in brackets e.g. `[codenameone] my search query` +---|--- + +### What you Shouldn’t Do + +Please don’t send us personal emails. + +The reason we provide free support is to help the community as a whole. When you send us a personal email +you are undermining that. + +__ | Since pro & enterprise users effectively subsidize our free version one of the benefits they get is private support +---|--- + +Please don’t post/send attachments that aren’t images: APK’s, IAP’s or whole projects. We can’t really run these +apps as our devices aren’t jailbroken, even if they were it probably wouldn’t tell us much…​ + +It’s hard dealing with all of these projects, in the past we used to let pro users send us their project sources but +even this is now impractical as our community grew larger. + +If you need to send us a test case you should do this thru git [as explained here](/blog/issue-submission-guideline.html). + +__ | Please keep in mind that what you see in terms of our support is the tip of the iceberg. Besides dealing with all +of these channels we spend a great deal of support resources on pro/enterprise & corporate accounts. So if our +responses are brief or hasty it’s due to the work overload +---|--- + +### What about Pro Support? + +Pro developers also have the ability to send private support email. + +Some pro developers started submitting their questions to stack overflow and just sending us a support email +with a link to the question. This is great as we can answer the question quickly but still provide the community +with information that might be important to other developers. + +If you can do that as a pro/enterprise developer that’s great but it’s not required. + +### Please Ask for Help + +This is a bit of a long post so it might be intimidating to some but that is not it’s goal! + +We want to help as much as we can which is why we have so many open channels and we understand that this +might be confusing. + +**Don’t be afraid to ask in the wrong place!** + +At most we’ll just refer you to the right location for your question. +We think support is the most important thing we can do as a company and I hope that’s the message that we +are getting thru. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Aquila CodenameOne** — July 19, 2016 at 1:13 pm ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-22698)) + +> Aquila CodenameOne says: +> +> for orientation I am using orientation-listener in my app and also put Logger code in orientation-listener some time orientation listener is not called when I rotate screen in my android tablet +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **Shai Almog** — July 20, 2016 at 4:31 am ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-21455)) + +> Shai Almog says: +> +> As the article above states, these things should be asked in StackOverflow or in a relevant blog post or in the discussion forum. I see you did the former which is great: [http://stackoverflow.com/qu…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **madhu thestudent** — August 19, 2016 at 9:10 am ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-21460)) + +> madhu thestudent says: +> +> My applicaiton need to show the notifications,So i used localnotification in codename one.But it supports only for android mobiles not for tablets,what should i do to support for tablets also? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **madhu thestudent** — August 19, 2016 at 9:15 am ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-22862)) + +> madhu thestudent says: +> +> can you please tell ,from which version of android tablets does the codename one notification support . +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **Shai Almog** — August 20, 2016 at 4:21 am ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-22794)) + +> Shai Almog says: +> +> This isn’t a generic question and answer section. Please read the above article… +> +> I’m guessing you don’t have an Android tablet. You probably have a Kindle or some other clone without Google Play services. Some features aren’t available when that is missing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **Peter Hric** — September 5, 2016 at 2:43 pm ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-22907)) + +> Peter Hric says: +> +> Hi, Can I change and use the template project with Leather theme and Tab Application template ? +> Cuz the GUI builder just does not let me change anything 🙁 +> looks like its locked +> +> I have learned many important informations from your chat-support, but they could not definitely state how to edit those sample app themes. +> +> Many thanx in advance ! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **Shai Almog** — September 6, 2016 at 3:53 am ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-22897)) + +> Shai Almog says: +> +> Yes, this should work fine. You won’t be able to delete elements that are currently being used. +> +> Other than that everything should work fine. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **Emmanuel Njoku** — September 22, 2016 at 7:51 pm ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-23158)) + +> Emmanuel Njoku says: +> +> This is an error: +> java.net.URISyntaxException: Illegal character in path at index 9: showForm(“Main”, null) +> at java.net.URI$[Parser.fail](:2848) +> at java.net.URI$Parser.checkChars([URI.java]():3021) +> at java.net.URI$Parser.parseHierarchical([URI.java]():3105) +> at java.net.URI$Parser.parse([URI.java]():3063) +> at java.net.URI.([URI.java]():588) +> at com.codename1.impl.javase.JavaSEPort.execute([JavaSEPort.java]():5630) +> at com.codename1.ui.Display.execute([Display.java]():2858) +> at com.codename1.ui.util.UIBuilder$FormListener.actionPerformed([UIBuilder.java]():2854) +> at com.codename1.ui.util.EventDispatcher.fireActionEvent([EventDispatcher.java]():349) +> at com.codename1.ui.Form.actionCommandImplNoRecurseComponent([Form.java]():1593) +> at com.codename1.ui.Button.fireActionEvent([Button.java]():407) +> at com.codename1.ui.Button.released([Button.java]():442) +> at com.codename1.ui.Button.pointerReleased([Button.java]():530) +> at com.codename1.ui.Form.pointerReleased([Form.java]():2623) +> at com.codename1.ui.Form.pointerReleased([Form.java]():2559) +> at com.codename1.ui.Component.pointerReleased([Component.java]():3223) +> at com.codename1.ui.Display.handleEvent([Display.java]():2022) +> at com.codename1.ui.Display.edtLoopImpl([Display.java]():1067) +> at com.codename1.ui.Display.mainEDTLoop([Display.java]():996) +> at [com.codename1.ui.RunnableWr…](:120) +> at [com.codename1.impl.Codename…](:176) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **Shai Almog** — September 23, 2016 at 4:35 am ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-22923)) + +> Shai Almog says: +> +> It looks like you set the “execute” value in the GUI builder command to something that isn’t a URL. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **Raghu vasa** — September 29, 2016 at 7:53 am ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-21464)) + +> Raghu vasa says: +> +> Hi, +> I am loading html pages using Codenameone BrowserComponent. And My app is already in play store and installed in android device. Now i want to open play store with my appid as Installed. But it is opening play store in browser with “Install ” option. If I click on Install option it is asking for my account credentials. Now if I sign in it is opening play store with “Installed” option. +> +> Why it is asking again for sign in. I want to open the play store with Installed option. How Can I achieve this functionality. +> +> Thanks, +> Raghu +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **Shai Almog** — September 30, 2016 at 6:50 am ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-22890)) + +> Shai Almog says: +> +> Hi, +> the web login is different from the phone login. A web session you embed in the app doesn’t have the login credentials of the device since that will violate device isolation policies. Just to be clear this is a security measure from Google that we can’t control. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **Aquila CodenameOne** — October 19, 2016 at 12:18 pm ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-22820)) + +> Aquila CodenameOne says: +> +> Hi, +> +> I am installed a Codename one App in my mobile device, I would like to know the app version number in app startup, +> if it is possible how to write the code in Codename one. +> +> Thanks, +> Sateesh. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + + +### **Shai Almog** — October 20, 2016 at 2:11 am ([permalink](https://www.codenameone.com/blog/clarifying-our-support.html#comment-23052)) + +> Shai Almog says: +> +> Hi, +> it’s in Display.getProperty() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fclarifying-our-support.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/clearable-text-field.md b/docs/website/content/blog/clearable-text-field.md new file mode 100644 index 0000000000..65a864d229 --- /dev/null +++ b/docs/website/content/blog/clearable-text-field.md @@ -0,0 +1,40 @@ +--- +title: Clearable Text Field +slug: clearable-text-field +url: /blog/clearable-text-field/ +original_url: https://www.codenameone.com/blog/clearable-text-field.html +aliases: +- /blog/clearable-text-field.html +date: '2017-06-05' +author: Shai Almog +--- + +![Header Image](/blog/clearable-text-field/new-features-6.jpg) + +A common request over the past couple of years has been to add a text field that supports a clear button in the end, we used to have a common answer on how this can be implemented but we didn’t have an actual implementation builtin despite this being a relatively common request. + +At first I thought this is something we should implement natively but it turns out that this doesn’t exist natively in Android so we just implemented this as a wrapper to the TextField e.g. replace this: + + + cnt.add(myTextField); + +With this: + + + cnt.add(ClearableTextField.wrap(myTextField)); + +You can also specify the size of the clear icon if you wish. This is technically just a `Container` with the text field style and a button to clear the text at the edge. + +### Global Context Update + +After posting about [the new CN class](/blog/static-global-context.html) last week we added a lot of new features into it. The API now supports capabilities from `FileSystemStorage` & `Storage` both of which should allow easier storage. + +We are still a bit conflicted about some of the more elaborate API’s such as database, contacts etc. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/clock-demo.md b/docs/website/content/blog/clock-demo.md new file mode 100644 index 0000000000..af4d194ffd --- /dev/null +++ b/docs/website/content/blog/clock-demo.md @@ -0,0 +1,37 @@ +--- +title: Clock Demo +slug: clock-demo +url: /blog/clock-demo/ +original_url: https://www.codenameone.com/blog/clock-demo.html +aliases: +- /blog/clock-demo.html +date: '2016-06-22' +author: Shai Almog +--- + +![Header Image](/blog/clock-demo/clock-demo.png) + +We’ve been working very hard on updating a very ambitious demo for this week but alas it still isn’t ready…​ In the +meantime we decided to modernize the clock demo which is an important demo that is missing from the IDE’s for +some reason which is a shame because it’s probably our only low level graphics focused demo…​ + +**Check out a live preview of the demo on the right here thanks to our JavaScript port!** + +This demo was developed by Steve as part of a tutorial to teach low level graphics programming, this tutorial +was folded into the [developer guide graphics section](/manual/graphics.html). Due to it’s nature there is +not much we can improve about the demo. It’s a wonderful demo both in simplicity and scope. + +Still we modernized some of the boilerplate code that was improved since the original demo. +We also updated the fonts which really took the demo to the next level. We had some other thoughts but this +is one of those cases where adding features would probably detract from the value of the demo so we left it as it is. + +You can check out the slightly modified source code of this demo in +[this github project](https://github.com/codenameone/ClockDemo). + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/cloud-files.md b/docs/website/content/blog/cloud-files.md new file mode 100644 index 0000000000..e6baa2560c --- /dev/null +++ b/docs/website/content/blog/cloud-files.md @@ -0,0 +1,131 @@ +--- +title: Cloud Files +slug: cloud-files +url: /blog/cloud-files/ +original_url: https://www.codenameone.com/blog/cloud-files.html +aliases: +- /blog/cloud-files.html +date: '2014-03-09' +author: Shai Almog +--- + +![Header Image](/blog/cloud-files/cloud-files-1.png) + + + + +[ +![Map](/blog/cloud-files/cloud-files-1.png) +](/img/blog/old_posts/cloud-files-large-2.png) + + + +Cloud files are a great pro feature that we didn’t emphasize enough, its remarkably useful. It allows you to upload a file into the cloud which you can then transfer to anyone thru a simple “obfuscated” URL. The URL is long so the probability of someone guessing it is low, hence its pretty secure for private file transfer (if its really private you should use +[ +bouncy castle +](http://www.codenameone.com/3/post/2013/06/bouncy-castle-crypto-api.html) +). The API couldn’t be simpler: + + + + + + +String fileId = CloudStorage.getInstance() + + +.uploadCloudFile(mimeType, fileName); + + + + + +This will block to upload the file so you might want to display an infinite progress indicator or something, once its done and the file was uploaded you can just call: + + + + +String url = CloudStorage.getInstance(). + + +getUrlForCloudFileId + +( + +fileId); + + + + +That URL will provide you with the file download and you can delete the file via deleteCloudFile(fileId). In the upcoming version we are also adding deleteAllCloudFilesForUser() and deleteAllCloudFilesBefore(timestamp, developerAccount, developerPassword) + + +which will allow you to purge some of your quota. + + + + +You can use this for image exchange and other such tricks but one of my favorite concepts is sharing data between devices e.g. you can upload your application state as a file to the cloud and expose it via a QR code like this: + + +int size = Math.min(Display.getInstance().getDisplayWidth(), Display.getInstance().getDisplayHeight()); + + + + + + +Label qrCode = new Label(new URLImage(“http://chart.apis.google.com/chart?cht=qr&chs=” + size + “x” + size “&chl=” + fileId + “&chld=H|0”)); + + + + + + +Now on the other device just scan the QR code and download the file to import the data, trivial synchronization between devices without typing a single word into the device! + + + + +The image you see on the right is a bit unrelated but you might find it interesting… + +A corporate account requested + +native Google Maps support for iOS/Android, we already have a prototype on iOS although Android is a bit more of a challenge. We hope to have something to show soon though. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — March 10, 2014 at 7:01 pm ([permalink](https://www.codenameone.com/blog/cloud-files.html#comment-22012)) + +> Anonymous says: +> +> Hey Shai, +> +> what about Windows Phone? will it have native maps support too? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcloud-files.html) + + +### **Anonymous** — March 11, 2014 at 5:02 am ([permalink](https://www.codenameone.com/blog/cloud-files.html#comment-21658)) + +> Anonymous says: +> +> That isn’t planned at the moment. On Windows Phone we will currently fallback to MapComponent. Google Maps doesn’t have a version for Windows Phone so supporting something like here maps etc. might be a pain. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcloud-files.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/cloud-object-viewer.md b/docs/website/content/blog/cloud-object-viewer.md new file mode 100644 index 0000000000..b31e134dac --- /dev/null +++ b/docs/website/content/blog/cloud-object-viewer.md @@ -0,0 +1,47 @@ +--- +title: Cloud Object Viewer +slug: cloud-object-viewer +url: /blog/cloud-object-viewer/ +original_url: https://www.codenameone.com/blog/cloud-object-viewer.html +aliases: +- /blog/cloud-object-viewer.html +date: '2013-04-29' +author: Shai Almog +--- + +![Header Image](/blog/cloud-object-viewer/cloud-object-viewer-1.png) + + + + +[ +![Picture](/blog/cloud-object-viewer/cloud-object-viewer-1.png) +](/img/blog/old_posts/cloud-object-viewer-large-2.png) + +Working with the +[ +Cloud Object API +](/javadoc/com/codename1/cloud/package-summary.html) +can sometimes be difficult. The data isn’t tabular and understanding the concepts such as indexes and scopes for such objects is pretty hard. + + +To help alleviate this difficulty Chen built a tool right into the Codename One simulator that allows you to query the cloud storage for the current application and helps you review some of the complexities involved. + + +You can query various application scopes, if you don’t enter an object type you will receive all objects but only for the private/application scopes (otherwise you would just get too much information). Notice that when you sort based on an index if the index is missing an entry just won’t appear so keep that in mind. + + +We have great plans for this API, including features for map-reduce like functionality to allow you to build complex data manipulation logic without having to setup any server infrastructure. + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.md b/docs/website/content/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.md new file mode 100644 index 0000000000..68320c506d --- /dev/null +++ b/docs/website/content/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.md @@ -0,0 +1,764 @@ +--- +title: Building Cloud-powered Native Mobile Apps with Parse.com and Codename One +slug: cloud-powered-mobile-apps-with-parse-and-codenameone +url: /blog/cloud-powered-mobile-apps-with-parse-and-codenameone/ +original_url: https://www.codenameone.com/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.html +aliases: +- /blog/cloud-powered-mobile-apps-with-parse-and-codenameone.html +date: '2015-09-06' +author: Steve Hannah +--- + +![Header Image](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/parse.com-post-header.jpg) + +A couple of weeks ago I created a [simple social network app](https://github.com/shannah/social-network) as part of the [Codename One webinar](https://www.codenameone.com/blog/java-mobile-dev-webinar-recap.html). This app provided functionality similar to the Facebook app. + + 1. Send and Accept friend requests + + 2. Post news + + 3. View news items posted by you and your friends + +For the server, I used a [PHP/MySQL REST interface](https://github.com/shannah/social-network-server/blob/master/actions/friends_api.php), and wrote a very [thin client](https://github.com/shannah/social-network/blob/master/social-network/src/com/codename1/demos/socialnet/SocialClient.java) in Codename One. Both the [server](https://github.com/shannah/social-network-server) and [client](https://github.com/shannah/social-network) project are on GitHub so you can review it and install it yourself on your own server. + +Some screenshots of the app running in the Codename One Simulator: + +![Social app screenshots](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/social-app-screenshots.png) + +I decided to port this app to [Parse.com](http://parse.com) as a proof-of-concept. + +Here is a 3-minute screencast of the app powered by Parse.com: + +## What is Parse.com? + +Parse.com is like a back-end in a box. You get a highly scalable REST server and NoSQL database without having to manage it yourself. This allows you to focus on your Codename one client app – making it slick and beautiful. No worries about scaling, server software patches, or any of that noise. Just the app. + +I particularly like the fact that Parse.com is free for apps that get a small amount of traffic (up to 30 requests per second). As your app grows, you just pay for the added bandwidth. + +## A Birds-Eye View of the Porting Process + +I started with a fully functional app. The only portion of the Codename One app that required changes was the [`SocialClient` class](https://github.com/shannah/social-network/blob/master/social-network/src/com/codename1/demos/socialnet/SocialClient.java), which is where all of the interaction with the server happened. + +On the server side, the process was roughly: + + 1. Sign up for an account on Parse.com + + 2. Create a new App ID + + 3. Set up my data model + + 4. Implement a thin REST interface for my data using Parse’s cloud functions. + +## The Client API + +The full API for [this class](https://github.com/shannah/cn1-social-network-parse/blob/master/src/com/codename1/demos/parse_social/SocialClientParse.java) is as follows: + + + // Registers new user + public void register(String username, String password) throws IOException; + + // Logs in as user + public void login(String username, String password) throws IOException; + + // Logs current user out + public void logout() throws IOException; + + // Gets list of friends of current user + public List getFriends() throws IOException; + + // Finds users with username matching query string + public List findUsers(String query) throws IOException; + + // Finds pending friend requests for current user + public List getPendingFriendRequests() throws IOException; + + // Sends a friend request to given user + public void sendFriendRequest(String username) throws IOException; + + // Accepts a friend request from a given user + public void acceptFriendRequest(String username) throws IOException; + + // Decline a friend request from a given user + public void declineFriendRequest(String username) throws IOException; + + // Gets the profile of a given user + public Map getProfile(String username) throws IOException; + + // Updates the profile of a given user with specified values + public void updateProfile(Map profile) throws IOException; + + // Posts a news item + public long post(Map post) throws IOException; + + // Gets the news feed for the given user + public List getFeed(Date olderThan) throws IOException; + + // Gets the username of the current user + public String getUsername(); + +To interact with the [PHP/MySQL back-end](https://github.com/shannah/social-network-server/blob/master/actions/friends_api.php) this API was implemented directly on top of `ConnectionRequest` and the `NetworkManager` to issue HTTP GET and POST requests directly to the server. JSON was used to transmit the response back from the server to the client, and this was converted into `Map`s and `List`s. + +__ | You’ll notice that this API does not make use of Java’s strong typing…​ I’m just using lists and maps. This was for flexibility while I was fleshing out the API. At some point, in a real-world app, I would probably refactor to use some custom Java types. +---|--- + +For the Parse back-end we could also just write a thin REST client on top of `ConnectionRequest`, but there is an easier way, thanks to Chidiebere Okwudire’s [parse4cn1](https://github.com/sidiabale/parse4cn1) cn1lib, which wraps the [Parse REST API](https://parse.com/docs/rest/guide/) providing a Java API that is very similar to the official [Parse Java API](https://parse.com/docs/android/guide). + +## Creating the Parse App + + 1. Log into Parse.com + + 2. Create a new App + +## Creating the Data Model + +Once your app has been created you need to create your data model. In Parse.com this is done by defining a set of classes. This is analogous to creating tables in an SQL database. In order to motivate this exercise, let’s take a look at the schema for the MySQL database in the previous version. The following is the PHP (with embedded SQL code) that was used to generate the database: + + + + +For the Parse data model, my first instinct was to just create a class for each table. However, I discovered that that a one-to-one mapping was not ideal. This is due, in part, to the fact that Parse already provides some of the functionality out of the box, and also that Parse’s database is not relational as MySQL is. + +__ | Parse supports relations but they work a little bit different than they do in a relational database like MySQL. We’ll explore the differences in more detail later. +---|--- + +In the end, I settled on the following classes for my the app: + + 1. `User` – For user accounts. I folded the `profile` table data into this single class as well to simplify the model. + + 2. `Post` – For news items posted by users. + +### Step By Step : Creating the Data Model + +#### Creating the “User” class + + 1. In the “Data” section of the “Core” tab, click on “Add Class”: + +![Add class button](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/c0310d16-4d66-11e5-8e21-509e44e4f3bb.png) + + 2. Select “User” from the dialog, and click “Create Class”: + +![Create user class](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/d83039dc-4d66-11e5-8c00-7d19b3ba56e3.png) + + 3. **Create screen_name column**. Click the “+ Col” button on the top menu. + +![User class details](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/e530ac48-4d66-11e5-8e78-eb23f5ac216a.png) + +Then select type = “String” and name = “screen_name”: + +![Create screen_name column](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/fa79f3e8-4d66-11e5-8d80-f76b0bd0ca10.png) + + 4. **Create avatar column** of type “File”: + +![Create avatar column](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/0d569200-4d67-11e5-89dc-4cb5397bfaf8.png) + + 5. **Add “friends” and “pendingFriendRequests” relations.**. Add them as columns of type “Relation”: + +![Add friends column](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/1f6f2ff6-4d67-11e5-94ef-99c25a29fb5e.png) + +![Add pendingFriendRequests column](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/33edbb64-4d67-11e5-8902-936c82ee7658.png) + +#### Creating the “Post” class + + 1. Create a new class named “Post”: + +![New post class](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/4bad51a6-4d67-11e5-982d-171387d2cb83.png) + + 2. Add “comment” column. + +![Add comment column](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/59b01482-4d67-11e5-9f3e-5597adb48fc4.png) + + 3. Add “photo” column with type “File”: + +![Add photo column](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/6d7ea848-4d67-11e5-875b-e041168d5671.png) + + 4. Add “postedBy” column as type “Pointer” to the “_User” class: + +![Add postedBy column](/blog/cloud-powered-mobile-apps-with-parse-and-codenameone/7fb2cc74-4d67-11e5-9fb7-0a439670a154.png) + +### Uploading Files + +I also ended up creating an `Upload` class but this was purely to help with file uploads, and is not part of the conceptual design. + +### Aren’t we missing a lot of tables?!! + +How did we reduce a database down from 6 tables to only 2 classes? Well: + + 1. The `sessions` table is no longer necessary in Parse because Parse takes care of all aspects of user registration, login, and session management. + + 2. As mentioned before, I just folded the `profiles` data directly into the `User` class. This was for simplicity and to minimize the number of data requests to obtain profile data. + + 3. The `friends` and `friend_requests` tables were join tables meant to relate users to each other. In Parse, we handle this by adding a column of type `Relation` to our classes. E.g. The `User` class has a `friends` relation and an `pendingFriendRequests` relation that provide equivalent functionality to the `friends` and `friend_requests` tables. + +### Relations + +As I mentioned above, relations are handled a little differently in Parse than in a relational database. Parse provides two column types for “pointing” to other records in the database: + + 1. **Pointer** – A type you can use for adding a reference to a single record in that column. E.g. If you wanted to track if a User was the parent of another User, you might add a column named “parent” to the “User” class with type “Pointer”. + + 2. **Relation** – A type used for storing references to multiple records in that column. E.g. If you wanted to track all of the children of a User, you might add a column to the “User” class named “children” with type “Relation”. + +In our data model, we needed to track two relationships between user records: + + 1. Whether they are friends + + 2. Whether there is a pending friend request from one to the other. + +So I added a columns named “friends” and “pendingFriendRequests” to the “User” class, both with type “Relation”. + +__ | Relationships are one-way only. E.g. If you add “Steve” to the friends relation of “Doug”, then that does not automatically add “Doug” to “Steve”‘s friends relation. For the “pendingFriendRequests” relationship this is what we want anyways, but for the “friends” relationship we wanted it to be two-way, so we need to add Steve to Doug and Doug to Steve when making them friends. +---|--- + +## Accessing the Database from Codename One + +Now that we have our database set up, let’s try to connect to it from our Codename one app. + +### Installing parse4cn1 library + +The first thing that we need to do is download and install the `parse4cn1` library. You can download it from [here](https://github.com/sidiabale/parse4cn1). + +Copy the `parse4cn1.cn1lib` file into your project’s `lib` directory, then select “Refresh” libs (i.e. right click on the project > “Codename One” > Refresh Libs). + +You will also need to install the [CN1JSON library](https://github.com/shannah/CN1JSON/raw/master/dist/CN1JSON.cn1lib) which the parse4cn1 library depends on. + +### Initializing the Parse4CN1 API + +Before we do anything else, we need to initialize the Parse API by calling `Parse.initialize()` method. I place this method inside the constructor for my client class: + + + public SocialClientParse() { + Parse.initialize("", ""); + } + +The Application ID and client key can be found in the “Keys” tab when logged in to Parse.com. + +__ | Make sure to use the “Client Key” and not the “REST API Key” or “Master Key” when connecting to Parse from a client device, as is most likely the case with Codename One apps. The REST API key and Master Key provide full permissions to your database and should not be embedded anywhere in your app for security reasons. These keys are for use in secure settings like a server-side application that connects to your parse application. +---|--- + +### Logging In + +The implementation of the login method for our REST client is as follows. + + + ParseUser user; + String token; + ... + + public void login(String username, String password) throws IOException { + try { + user = ParseUser.create(username, password); + user.login(); + token = user.getSessionToken(); + } catch (ParseException ex) { + Log.e(ex); + throw new IOException(ex.getMessage()); + } + + } + +and logging out: + + + public void logout() throws IOException { + try { + user.logout(); + user = null; + token = null; + } catch (ParseException ex) { + Log.e(ex); + throw new IOException(ex.getMessage()); + } + } + +### User Registration + +User registration is very similar to logging in. It just uses the `ParseUser.signUp()` method instead of `ParseUser.login()`. + + + public void register(String username, String password) throws IOException { + try { + ParseUser user = ParseUser.create(username, password); + user.put("screen_name", username); + user.signUp(); + + + } catch (ParseException ex) { + Log.e(ex); + throw new IOException(ex.getMessage()); + } + } + +## The rest of the REST API + +The Parse API provides support for CRUD (Create-Read-Update-Delete) directly from the client to the data source. For security it supports ACLs at both the class-level and the object level. Therefore, if you set up your ACLs appropriately, you could interact with the database directly from your Codename one client app. You can see API examples [on the parse4cn1 wiki](https://github.com/sidiabale/parse4cn1/wiki/Usage-Examples#objects). + +**Here are a few reasons why you should NOT do this** + + 1. **Offering direct database access to the client makes the app very difficult to secure**. Any server-side engineer worth a salt know that **YOU CANNOT TRUST THE CLIENT**. If you want actions to be available to some users but not others – and they are using the same client app, then you need to be **very** careful about the ACLs that you use in your database. + + 2. Some operations may require multiple database requests which can slow the app down. Better to just send a single request to the parse server, and let server-side code handle the multiple queries. + +### Cloud Code + +Parse allows you to implement server-side REST web services, known as “cloud code”. Because this code is running on the server side, you can allow them to run with the master key – so you don’t have to rely on ACLs to limit access to records and classes. You can use your own logic to decide who can do what. This model maps more closely to running your own server and provides more control. AND it allows you to lock down your database so you don’t need to provide direct access to clients. + +Cloud code uses the [Parse Javascript API](https://parse.com/docs/js/guide) – which is equivalent to the REST and Java APIs. In order to use them, you need to install the [parse command-line tools](https://parse.com/apps/quickstart#cloud_code). + +### Creating Local Cloud Code Project + +It allows you to create a local version of the Parse app, in so much as developing cloud code is concerned. Here is the readout of `parse new`, the command for setting up the local development project: + + + Steves-iMac:social-network-parse shannah$ parse new + Please log in to Parse using your email and password. + Email: [[email protected]](/cdn-cgi/l/email-protection) + Password (will be hidden): + Would you like to create a new app, or add Cloud Code to an existing app? + Type "(n)ew" or "(e)xisting": e + 1: Social Demo + Select an App to add to config: 1 + Awesome! Now it's time to setup some Cloud Code for the app: "Social Demo", + Next we will create a directory to hold your Cloud Code. + Please enter the name to use for this directory, + or hit ENTER to use "Social Demo" as the directory name. + + Directory Name: social-demo-parse-2 + Your Cloud Code has been created at /Users/shannah/cn1_files/incubator/social-network-parse/social-demo-parse-2. + Next, you might want to deploy this code with "parse deploy". + This includes a "Hello world" cloud function, so once you deploy + you can test that it works, with: + + curl -X POST + -H "X-Parse-Application-Id: xxxxxxxxxxxxxxxxxx" + -H "X-Parse-REST-API-Key: xxxxxxxxxxxxxxxxxxxx + -H "Content-Type: application/json" + -d '{}' + https://api.parse.com/1/functions/hello + +This creates a scaffold for my app project in the directory “social-demo-parse-2”. The directory structure is: + + + ./cloud + ./cloud/main.js + ./config + ./config/global.json + ./public + ./public/index.html + +The only file that matters here is the `./cloud/main.js` file, which will include all of the cloud code. It starts you off with a nice sample “hello” function that can be called via the REST API. Its contents are as follows: + + + // Use Parse.Cloud.define to define as many cloud functions as you want. + // For example: + Parse.Cloud.define("hello", function(request, response) { + response.success("Hello world!"); + }); + +This is a simple function that simply returns the string “Hello world!”. You can call this function directly from your Codename One app by simply calling: + + + String result = (String)ParseCloud.callFunction("hello", null); + System.out.println(result); // Hello world! + +### Writing End Points for the REST API + +Now, we just need to create end points for all of our client’s pertinent functions. Let’s start by inserting placeholders for our API end points: + + + Parse.Cloud.define("send_friend_request", function(request, response) { + ... + }); + + Parse.Cloud.define("accept_friend_request", function(request, response) { + ... + }); + + Parse.Cloud.define("decline_friend_request", function(request, response) { + + }); + + Parse.Cloud.define("get_pending_friend_requests", function(request, response) { + + }); + + Parse.Cloud.define("get_friends", function(request, response) { + + }); + + Parse.Cloud.define("post", function(request, response) { + + }); + + Parse.Cloud.define("update_profile", function(request, response) { + + }); + + Parse.Cloud.define("get_profile", function(request, response) { + + }); + + Parse.Cloud.define("get_feed", function(request, response) { + + }); + + Parse.Cloud.define("find_users", function(request, response) { + + }); + +In order to remain consistent with the PHP/MySQL REST API in the previous version, we will have these end points always return a JSON object with the following form: + + + //For errors: + {code : 500, message : "Some error message", ...} + + // For successes + {code : 200, ... } + +That way the client can always check the “code” property to find out if the action was successful. + +For successful operations, there may be three types of return values: + + 1. No return value. E.g. `accept_friend_request`, `send_friend_request`. + + 2. Returns a list of objects. E.g. `find_users`, `get_friends`, etc.. + + 3. Returns a single object. E.g. `get_profile` + +### Writing Codename One Web Service Client + +So on the client side (in our Codename One app), I created 3 utility wrappers to handle these cases: + + + /** + * Calls cloud code function with void return type. + * @param funcName The name of the function to call. + * @param params Parameters passed to the function. Accepts null. + */ + private void callFunc(String funcName, Map params) throws IOException { + try { + JSONObject response = (JSONObject)ParseCloud.callFunction(funcName, params); + int code = response.getInt("code"); + if (code != 200) { + throw new IOException(response.getString("message")); + } + } catch (Throwable ex) { + Log.e(ex); + ex.printStackTrace(); + throw new IOException(ex.getMessage()); + } + } + + /** + * Calls a cloud code function whose result will be a list of objects. + * @param funcName The name of the cloud code function to call. + * @param params Parameters passed to the cloud code. Accepts null. + * @param listKey The JSON key in the response object that contains the list of objects that + * were returned by the cloud code. + */ + private List getList(String funcName, Map params, String listKey) throws IOException { + try { + JSONObject response = (JSONObject)ParseCloud.callFunction(funcName, params); + System.out.println(response); + int code = response.getInt("code"); + if (code != 200) { + throw new IOException(response.getString("message")); + } else { + ArrayList out = new ArrayList(); + JSONArray posts = response.getJSONArray(listKey); + int len = posts.length(); + for (int i=0; i getFeed(Date olderThan) throws IOException { + return getList("get_feed", "posts"); + } + +### Sending, Getting, & Accepting Friend Requests + +Recall from our database design that friends and friend requests are supported via the “friends” and “pendingFriendRequests” relations in the users table. Sending a friend request to a user involves, adding the current user to the “pendingFriendRequests” relation of that user. Accepting a friend request from a user involves adding the current user to that user’s “friends” relation, adding that user to the current user’s “friends” relation, and removing that user from the current user’s “pendingFriendRequests” relation. The code for `send_friend_request` is as follows: + + + Parse.Cloud.define("send_friend_request", function(request, response) { + Parse.Cloud.useMasterKey(); + + (new Parse.Query(Parse.User)).equalTo("username", request.params.username).each(function(friend) { + friend.relation("pendingFriendRequests").add(Parse.User.current()); + friend.save().then(function(result) { + response.success({code: 200, message: "Successfully sent friend request"}); + }); + }); + + }); + +**Some things to note here:** + + 1. `Parse.Cloud.useMasterKey()` gives us carte blanche on the parse API. We don’t have any security restrictions. Without this all access would be subject to security restrictions on the currently logged in user. + + 2. `(new Parse.Query(Parse.User)).equalTo("username", request.params.username).each(function(friend) {` + +Creates a query on the User class for all users with “username” equal to the “username” parameter passed as part of the request. The `each()` method then iterates over the results with the provided callback. + + 3. `friend.relation("pendingFriendRequests").add(Parse.User.current());` + +Adds the current user to the “pendingFriendRequests” relation of the found user. + + 4. `friend.save().then(function(result) {` + +We save the user object. `save()` returns a [promise](http://www.html5rocks.com/en/tutorials/es6/promises/) so that calling `then()` will result in us being able to defer what comes next until the save is complete. If you’re not familiar with promises, it’s really just cute syntax for a callback. + + 5. `response.success({code: 200, message: "Successfully sent friend request"});` + +This finally returns the response to the client as a JSON object. + +The code for getting a list of the pending friend requests is as follows: + + + Parse.Cloud.define("get_pending_friend_requests", function(request, response) { + Parse.Cloud.useMasterKey(); + + var out = []; + var user = Parse.User.current(); + user.relation("pendingFriendRequests").query().each(function(friend) { + out.push({ + sender : friend.get("username"), + receiver : user.get("username"), + avatar : friend.get("avatar") ? friend.get("avatar").url() : null, + screen_name : friend.get("screen_name") + + }); + }) + .then(function(result) { + response.success({code: 200, requests: out}); + }); + + }); + +And accepting pending friend requests: + + + Parse.Cloud.define("accept_friend_request", function(request, response) { + Parse.Cloud.useMasterKey(); + + var currentUser = Parse.User.current(); + var pendingRequests = currentUser.relation("pendingFriendRequests"); + + pendingRequests.query().equalTo("username", request.params.username).each(function(friend) { + currentUser.relation("friends").add(friend); + pendingRequests.remove(friend); + currentUser.save().then(function(result) { + friend.relation("friends").add(currentUser); + return friend.save(); + + }, function(error) { + response.success({code : 500, message : error}); + }).then(function(result) { + response.success({code: 200, message: "Friend request accepted"}); + }, function(error) { + response.success({code : 500, message : error}); + }); + }); + + }); + +### The Full Cloud Code Source + +You can view the full source for this cloud code [here](https://github.com/shannah/cn1-social-network-parse/blob/master/social_demo_parse_com/cloud/main.js). Each method follows roughly the same pattern: + + 1. Fetch some data from the database + + 2. Iterate through the results to build a JSON response. + +Some queries, especially queries involving complex relations like the one in `get_feed` were a little bit tricky to figure out, but in the end I was impressed by the Parse’s flexibility in being able to support quite complex queries. I won’t delve into the details here, but I will note that Parse’s documentation is exceptional and it seems to have quite a large user base, judging by the number of questions & answers related to parse that are already available online in their forums and elsewhere. I scarcely had to spend more than 5 minutes of googling to find the answer to my questions when I got stuck. + +## Build the App Yourself + +The full project, both the [Codename One client project](https://github.com/shannah/cn1-social-network-parse) and the [parse cloud code](https://github.com/shannah/cn1-social-network-parse/tree/master/social_demo_parse_com) are posted on Github to you can download and build the project yourself. + +## Install the App on Android + +I have posted an Android build of this app so you can install it directly on your phone is you wish: + + 1. [Download APK](https://github.com/shannah/cn1-social-network-parse/releases) +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — September 9, 2015 at 10:28 am ([permalink](https://www.codenameone.com/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.html#comment-22453)) + +> Interesting tutorial… +> +> I completely agree that the client should never be trusted (that’s also why parse4cn1 by design does not include any operations requiring the master key). However, I’m not convinced that it’s always a better/more secure idea (or even necessary) to write cloud code. +> +> The combination of ACLs, CLP (class level permissions) and the new pointer permissions [http://blog.parse.com/learn…]() is quite powerful and should be used when applicable. Applying that the CRUD, my feeling so far is that if the primary operation is “Read”, in-buit parse security measures are more than sufficient. For the “C”, “U”, and “D”, a per-case judgment is needed. Always reverting to cloud code might be a pitfall from other paradigms where such security measures as are present in Parse were missing. And it may slow down development with little or no added value. Of course, I’m neither a security expert nor a Parse expert so what am saying might not be completely correct; just food for thought 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcloud-powered-mobile-apps-with-parse-and-codenameone.html) + + +### **shannah78** — September 9, 2015 at 3:57 pm ([permalink](https://www.codenameone.com/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.html#comment-21560)) + +> “Security is inconvenient”, said Ashley Madison. The difficulty in securing an application increases exponentially with the number of access points. If you allow CRUD directly client side — or even just “R” — then you effectively have hundreds or thousands of access points (or millions depending on how you count). If your app has only a handful of “functions” though, you can limit the access point to just that handful and you can easily secure each point manually. +> +> Take the social network example. Even if the app were only read only (and it’s not), we have the challenge of allowing users to see only news items that were posted by their friends. Using the ACL method, every post would need to have an ACL entry for every friend of the poster. And when a friend is added or removed, the ACL entries for all posts of both friends would need to be modified accordingly. This, in itself is expensive and challenging, …. And it’s still easy to miss something. +> +> Further, you generally don’t want profile information to be readable by anyone other than someone’s friends. How would you provide this sort of limitation securely without cloud code? You can’t make the profiles table readable by everyone, so you would need to add ACLs at the record level – same problem as with the posts. The ACLs need to be added when profiles become friends, but +> +> Basically if you are doing *any* filtering client side for the purpose of security, your app is probably vulnerable to unauthorized access. That doesn’t mean that there aren’t occasions where you can get away with direct client-side CRUD. But you have to do a lot more thinking at each step. Or one day you’ll be “that guy” .. the guy who has to explain to his boss that the database was breached and client information was stolen. Don’t be that guy! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcloud-powered-mobile-apps-with-parse-and-codenameone.html) + + +### **Shai Almog** — September 9, 2015 at 4:24 pm ([permalink](https://www.codenameone.com/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.html#comment-22462)) + +> While I generally agree with all your points I wrote the app for my spouses yoga studio using this CRUD API on top of Parse. +> I can live with one lock (the parse keys) and since this isn’t an app for global distribution the chances of these getting hacked are pretty low. The fact that this isn’t a database of interest for hackers also makes it a safe choice. +> +> Writing a JavaScript DAO for the code seemed like a pain so I’m totally fine with that level of security. +> +> Maybe for the future version of the parse lib we should integrate TeaVM so we can write the server side code in Java too 😉 +> +> Note: that was a joke, please don’t do that! 😉 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcloud-powered-mobile-apps-with-parse-and-codenameone.html) + + +### **shannah78** — September 9, 2015 at 4:54 pm ([permalink](https://www.codenameone.com/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.html#comment-22471)) + +> Definitely agree that level of interest to hackers should be taken into consideration. The question I usually ask myself is “how bad would it be if this database were leaked to the world”. If the answer is anything worse than “it would be perfectly fine”, then designing for security should be top priority. That said, it *is* possible to write a secure app using the client-side CRUD API. It is just much harder. It requires a comprehensive understanding of Parse’s system – and also a lot more thought at each step of database design. +> +> I actually considered writing an ANT task to be able to write and deploy cloud code using TeaVM, but that would just be proof of concept. Most access point functions were trivial, and their Javascript API is quite nice to work with directly. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcloud-powered-mobile-apps-with-parse-and-codenameone.html) + + +### **Chidiebere Okwudire** — September 10, 2015 at 9:09 am ([permalink](https://www.codenameone.com/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.html#comment-22413)) + +> Thanks guys for sharing your thoughts. Security remains a difficult but very important subject and should be treated as such. +> +> @shannah78:disqus: One thing to bear in mind is that cloud code is not a silver bullet. It still needs to be combined with ACLs and/or CLPs. For instance, in the social networking example, all the security gains of using cloud code will be almost useless if the corresponding classes are still directly readable or even worse writable(!) to the public because anyone getting hold of the Parse app keys would wreak havoc by directly accessing the classes directly. That aspect is missing in the blog post. Please consider mentioning it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcloud-powered-mobile-apps-with-parse-and-codenameone.html) + + +### **shannah78** — September 11, 2015 at 5:09 am ([permalink](https://www.codenameone.com/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.html#comment-22298)) + +> You’re right that is missing from the post, and class level acls are still necessary to lock down the database when cloud code is used. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcloud-powered-mobile-apps-with-parse-and-codenameone.html) + + +### **SophiaVermon** — September 14, 2015 at 8:02 am ([permalink](https://www.codenameone.com/blog/cloud-powered-mobile-apps-with-parse-and-codenameone.html#comment-22151)) + +> Thanks for this detailed article with complete code and pictures, I will try to run it in my application. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcloud-powered-mobile-apps-with-parse-and-codenameone.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/cloud-storage-cloud-bindtm-iphone-5-simulator-barcodes-and-much-more.md b/docs/website/content/blog/cloud-storage-cloud-bindtm-iphone-5-simulator-barcodes-and-much-more.md new file mode 100644 index 0000000000..d72574cbfa --- /dev/null +++ b/docs/website/content/blog/cloud-storage-cloud-bindtm-iphone-5-simulator-barcodes-and-much-more.md @@ -0,0 +1,36 @@ +--- +title: Cloud Storage, Cloud Bind(tm), iPhone 5 simulator, barcodes and much more +slug: cloud-storage-cloud-bindtm-iphone-5-simulator-barcodes-and-much-more +url: /blog/cloud-storage-cloud-bindtm-iphone-5-simulator-barcodes-and-much-more/ +original_url: https://www.codenameone.com/blog/cloud-storage-cloud-bindtm-iphone-5-simulator-barcodes-and-much-more.html +aliases: +- /blog/cloud-storage-cloud-bindtm-iphone-5-simulator-barcodes-and-much-more.html +date: '2012-11-14' +author: Shai Almog +--- + +![Header Image](/blog/cloud-storage-cloud-bindtm-iphone-5-simulator-barcodes-and-much-more/codename-one-charts-1.png) + +We just made a major update including a pile of fixes and features. One of the biggest things we are launching right now is an early preview of our new Cloud Storage and Cloud Bind ™ solutions. + +Cloud Storage allows you to effectively use our cloud as a big object database, similar to other big data solutions as a sort of key/value pair lookup engine that allows you to share/sync between devices. + +The Cloud Bind ™ solution allows you to seamlessly bind components such as lists, text components etc. to the cloud where changes automatically persist to the Cloud Storage and data is automatically fetched from there. + +These are currently limited only to pro users mostly because we haven’t yet figured out the free quotas we want to allocate for free/basic users. We will publish more tutorials and information when we have this fleshed out. + +We also added an iPhone 5 simulator skin allowing you to generate iPhone 5 resolution screenshots. + +And we finally added a bar code/qr code reader API. However, this wasn’t as easy as one would suspect. The problem is that ZXing our API of choice for the QR code in the demo, doesn’t do barcodes on iOS… So we had to use a different implementation on iOS which might not be as good as ZXing with QR codes. So the old native approach will still work if you want it too, but you don’t have to because we have a much simpler API. + +There is allot more coming in the next couple of months… Stay tuned. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/cn1ml-javaone.md b/docs/website/content/blog/cn1ml-javaone.md new file mode 100644 index 0000000000..52c285e3b2 --- /dev/null +++ b/docs/website/content/blog/cn1ml-javaone.md @@ -0,0 +1,138 @@ +--- +title: CN1ML & JavaOne +slug: cn1ml-javaone +url: /blog/cn1ml-javaone/ +original_url: https://www.codenameone.com/blog/cn1ml-javaone.html +aliases: +- /blog/cn1ml-javaone.html +date: '2014-09-27' +author: Shai Almog +--- + +![Header Image](/blog/cn1ml-javaone/cn1ml-javaone-1.png) + + + + + +![CN1ML](/blog/cn1ml-javaone/cn1ml-javaone-1.png) + + + + + + +Shortly after introducing +[ +Mirah support for Codename One +](http://www.codenameone.com/blog/mirah-for-codename-one) +, Steve is back with something that is arguably even more impressive. Over the weekend Steve released a tool called +[ +CN1ML +](http://sjhannah.com/blog/?p=345) +which is an HTML subset markup language that allows you to effectively build Codename One UI’s with HTML. This isn’t another embedded webbrowser or HTMLComponent, this is a tool that statically translates HTML syntax into Codename One components. The benefit here is that you can keep all the advantages of using Codename One widgets (portability, performance, customizability etc.) with the HTML like syntax. + + + + +When we were at Sun, our manager Yoav Barel was heavily on our case for building exactly that and we effectively convinced him that its not feasible to do this since its too much work. I guess we should have known about Steve back then! + + +I think this is a very interesting idea and direction, one of the things I’d really like to see here is proper box model spanning behavior (float etc.) which is very tricky to do in Codename One today. Amazingly this is also very tricky to do natively in iOS/Android so we are all on the same boat… + + + + + + + + + + +* * * + +## Java One + + +We are here in the lovely city of San Francisco and having a blast, we have a pretty amazing announcement to make but until the contract is signed we’ll keep that low key. + + + +I’ll do a more detailed report on the complete trip, the parties and the booth but for now I’ll leave you with a few pictures I grabbed and some tags. + +[ +![](/blog/cn1ml-javaone/cn1ml-javaone-2.jpg) NetBeans party, small room crowded like a phone booth with great guys, food and beer ](/img/blog/old_posts/cn1ml-javaone-large-11.jpg "NetBeans party, small room crowded like a phone booth with great guys, food and beer") + +[ +![](/blog/cn1ml-javaone/cn1ml-javaone-3.jpg) NetBeans party left to right: Geertjan Wielenga, Shai Almog (me), Sean Phillips & Jens Deters ](/img/blog/old_posts/cn1ml-javaone-large-12.jpg "NetBeans party left to right: Geertjan Wielenga, Shai Almog \(me\), Sean Phillips & Jens Deters") + +[ +![](/blog/cn1ml-javaone/cn1ml-javaone-4.jpg) Our booth just after buildup on Sunday ](/img/blog/old_posts/cn1ml-javaone-large-13.jpg "Our booth just after buildup on Sunday") + +[ +![](/blog/cn1ml-javaone/cn1ml-javaone-5.jpg) Crowd at our session UGF8907: James Gosling, Robots, the Raspberry Pi and Small Devices ](/img/blog/old_posts/cn1ml-javaone-large-14.jpg "Crowd at our session UGF8907: James Gosling, Robots, the Raspberry Pi and Small Devices") + +[ +![](/blog/cn1ml-javaone/cn1ml-javaone-6.jpg) The stage our session UGF8907: James Gosling, Robots, the Raspberry Pi and Small Devices. Left to right Chen Fishbein, Shai Almog, James Gosling, José Pereda & Jens Deters ](/img/blog/old_posts/cn1ml-javaone-large-15.jpg "The stage our session UGF8907: James Gosling, Robots, the Raspberry Pi and Small Devices. Left to right Chen Fishbein, Shai Almog, James Gosling, José Pereda & Jens Deters") + +[ +![](/blog/cn1ml-javaone/cn1ml-javaone-7.jpg) Me and James Gosling on stage taken by Chen Fishbein ](/img/blog/old_posts/cn1ml-javaone-large-16.jpg "Me and James Gosling on stage taken by Chen Fishbein") + +[ +![](/blog/cn1ml-javaone/cn1ml-javaone-8.jpg) The selfi with James queue stretches down the stage ](/img/blog/old_posts/cn1ml-javaone-large-17.jpg "The selfi with James queue stretches down the stage") + +[ +![](/blog/cn1ml-javaone/cn1ml-javaone-9.jpg) Typical San Francisco: spinning class in the middle of a busy street with loud yelling and pedaling ](/img/blog/old_posts/cn1ml-javaone-large-18.jpg "Typical San Francisco: spinning class in the middle of a busy street with loud yelling and pedaling") + +[ +![](/blog/cn1ml-javaone/cn1ml-javaone-10.jpg) Highlight of the keynote, the kids of devoxxx4kids nailed it ](/img/blog/old_posts/cn1ml-javaone-large-19.jpg "Highlight of the keynote, the kids of devoxxx4kids nailed it") + + + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — September 30, 2014 at 11:40 am ([permalink](https://www.codenameone.com/blog/cn1ml-javaone.html#comment-21987)) + +> Anonymous says: +> +> This is really cool Steve, congratz ! 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcn1ml-javaone.html) + + +### **Anonymous** — September 30, 2014 at 1:25 pm ([permalink](https://www.codenameone.com/blog/cn1ml-javaone.html#comment-22235)) + +> Anonymous says: +> +> I was wondering if someone would do something like that specially because I’ve seen some apps that converts html5+css+javascript into smartphones apps. +> +> I’m really glad I found codenameone, specially because everything I found generated apps for Android, and I was searching form something cross plataform oriented. Gladly I found codenameone – I’m still suffering to learn, but I just need to write the app once. +> +> As a matter of fact I want to thank Shei, Chen and Eric for this great work, and now, thank Steve for this implementation that will help me a great deal because I’m very used to HTML. +> +> Regards. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcn1ml-javaone.html) + + +### **Anonymous** — October 19, 2014 at 10:44 am ([permalink](https://www.codenameone.com/blog/cn1ml-javaone.html#comment-24174)) + +> Anonymous says: +> +> wow steve you are a god. im getting started immediately. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcn1ml-javaone.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/cocoapods.md b/docs/website/content/blog/cocoapods.md new file mode 100644 index 0000000000..a75ac469ea --- /dev/null +++ b/docs/website/content/blog/cocoapods.md @@ -0,0 +1,139 @@ +--- +title: Cocoapods Support +slug: cocoapods +url: /blog/cocoapods/ +original_url: https://www.codenameone.com/blog/cocoapods.html +aliases: +- /blog/cocoapods.html +date: '2016-05-28' +author: Steve Hannah +--- + +![Header Image](/blog/cocoapods/cocoapods.png) + +[CocoaPods](https://cocoapods.org/) is a dependency manager for Swift and Objective-C Cocoa projects. +It has over eighteen thousand libraries and can help you scale your projects elegantly. Cocoapods can be +used in your Codename One project to include native iOS libraries without having to go through the hassle +of bundling the actual library into your project. Rather than bundling .h and .a files in your ios/native directory, +you can specify which “pods” your app uses via the `ios.pods` build hint. (There are other build hints also +if you need more advanced features). + +E.g.: + +To include the [AFNetworking](https://github.com/AFNetworking/AFNetworking) library in your app use the build +hint: + + + ios.pods=AFNetworking + +To include the [AFNetworking](https://github.com/AFNetworking/AFNetworking) version 3.0.x library in your app use +the build hint: + + + ios.pods=AFNetworking ~> 3.0 + +For full versioning syntax specifying pods see the +[Podfile spec for the “pod” directive](https://guides.cocoapods.org/syntax/podfile.html#pod). + +### Including Multiple Pods + +Multiple pods can be separated by either commas or semi-colons in the value of the `ios.pods` build hint. +E.g. To include GoogleMaps and AFNetworking, you could: + + + ios.pods=GoogleMaps,AFNetworking + +Or specifying versions: + + + ios.pods=AFNetworking ~> 3.0,GoogleMaps + +### Other Pod Related Build Hints + +`ios.pods.platform` : The minimum platform to target. In some cases, Cocoapods require functionality that is +not in older version of iOS. For example, the GoogleMaps pod requires iOS 7.0 or higher, so you would need to +add the `ios.pods.platform=7.0` build hint. + +`ios.pods.sources` : Some pods require that you specify a URL for the source of the pod spec. This may be +optional if the spec is hosted in the central CocoaPods source (``). + +### Converting PodFile To Build Hints + +Most documentation for Cocoapods “pods” provide instructions on what you need to add to your Xcode +project’s PodFile. Here is an example from the GoogleMaps cocoapod to show you how a PodFile can be +converted into equivalent build hints in a Codename One project. + +The GoogleMaps cocoapod directs you to add the following to your PodFile: + + + source 'https://github.com/CocoaPods/Specs.git' + platform :ios, '7.0' + pod 'GoogleMaps' + +This would translate to the following build hints in your Codename One project: + + + ios.pods.sources=https://github.com/CocoaPods/Specs.git + ios.pods.platform=7.0 + ios.pods=GoogleMaps + +__ | Note that the `ios.pods.sources` directive is optional +---|--- +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — January 24, 2017 at 2:14 am ([permalink](https://www.codenameone.com/blog/cocoapods.html#comment-23114)) + +> Chidiebere Okwudire says: +> +> This is really great! It’s made integrating the Parse iOS SDK *much* simpler. Thanks!! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcocoapods.html) + + +### **3lix** — February 13, 2017 at 3:55 pm ([permalink](https://www.codenameone.com/blog/cocoapods.html#comment-24126)) + +> 3lix says: +> +> Would these pods work on all three platforms (iOS, Android and Windows) or are these iOS specific? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcocoapods.html) + + +### **Shai Almog** — February 14, 2017 at 8:02 am ([permalink](https://www.codenameone.com/blog/cocoapods.html#comment-23239)) + +> Shai Almog says: +> +> No it’s designed for iOS native code. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcocoapods.html) + + +### **Francesco Galgani** — October 17, 2018 at 9:40 pm ([permalink](https://www.codenameone.com/blog/cocoapods.html#comment-23942)) + +> Francesco Galgani says: +> +> Is there anything similar for Android? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcocoapods.html) + + +### **Shai Almog** — October 18, 2018 at 4:04 am ([permalink](https://www.codenameone.com/blog/cocoapods.html#comment-23919)) + +> Shai Almog says: +> +> Sure, Gradle: [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcocoapods.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codapps-io-is-back-java-on-mobile-from-scratch.md b/docs/website/content/blog/codapps-io-is-back-java-on-mobile-from-scratch.md new file mode 100644 index 0000000000..0803f8a815 --- /dev/null +++ b/docs/website/content/blog/codapps-io-is-back-java-on-mobile-from-scratch.md @@ -0,0 +1,72 @@ +--- +title: Codapps.io is back Java on Mobile from Scratch +slug: codapps-io-is-back-java-on-mobile-from-scratch +url: /blog/codapps-io-is-back-java-on-mobile-from-scratch/ +original_url: https://www.codenameone.com/blog/codapps-io-is-back-java-on-mobile-from-scratch.html +aliases: +- /blog/codapps-io-is-back-java-on-mobile-from-scratch.html +date: '2016-09-21' +author: Shai Almog +--- + +![Header Image](/blog/codapps-io-is-back-java-on-mobile-from-scratch/codapps.png) + +We’ve discussed [codapps.io](http://codapps.io/) before, it’s a MOOC (online course) that allows you to learn Java +programming and uses mobile/Codename One as its vehicle. Our current documentation and tutorials can be quite +intimidating to a person who is a complete Java newbie so this course is quite helpful in bridging that gap. + +I think learning GUI programming is probably the best way to learn programming as it lets you “see” the results +instantly and experiment. + +The [codapps.io](http://codapps.io/) MOOC focuses on typical apps created with the GUI builder and tries to smooth +the entry into the lower level Java coding. + +Another interesting tutorial for complete beginners is from Loke Hansen and we discussed it +[here](/blog/how-to-build-a-clicking-tapping-game-tutorial.html). Hansen created a series of tutorials +covering the process of building a game from scratch without any experience in Java. He explains a lot of +complex details very clearly and because this is a game the course is both entertaining and goal oriented! + +### Other Resources + +We have a lot of documentation, but picking up a 900 page [developer guide](/manual/) might be intimidating +when you are completely new to Java. + +Here are some helpful resources to get you started: + + * [Component Gallery](https://www.codenameone.com/javadoc/com/codename1/ui/package-summary.html) – shows +the common components that are a part of Codename One in a visual index + + * [Layout gallery](https://www.codenameone.com/javadoc/com/codename1/ui/layouts/package-summary.html) – +layouts are one of the hardest concepts to grasp in Codename One, this visual gallery covers the basic Codename One +layout managers + + * [JavaDoc](https://www.codenameone.com/javadoc/) – the JavaDoc is a standard “reference guide” to the Codename One +API and what’s available in it you can search any method/class by clicking one of the index files +Developer guide + + * [Demos](/demos.html) – the Codename One demos e.g. the [Kitchen Sink](/demos-KitchenSink.html) are a +great place to start. You can create most demos by just going thru the wizard process by selecting +New Project → Codename One → Demos →#Name of demo# + +### Help + +Stack overflow is the best place to ask for help but it can sometimes be intimidating as you need to ask in the “right way” +& that can be difficult when you don’t know anything. Try asking on the [discussion forum](/discussion-forum.html) +notice that sometimes things get flagged as SPAM by the automatic Google filters. To avoid that you should probably +join the group before posting and use a verified gmail account. + +I learned Java by reverse engineering the first public beta and a lot of experimentation 20 years ago. Things that +are obvious to me might be baffling to people making their first steps into programming…​ +When you ask a question keep in mind that sometimes we might be detached from your current experience level +and guide us toward the type of answer you need. + +Keep in mind that engineering, math and all such disciplines eventually boil down to patience. Putting in the hours, +effort and asking for help when necessary will eventually pay off. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/code-freeze-for-3-3-performance.md b/docs/website/content/blog/code-freeze-for-3-3-performance.md new file mode 100644 index 0000000000..4ac739116f --- /dev/null +++ b/docs/website/content/blog/code-freeze-for-3-3-performance.md @@ -0,0 +1,45 @@ +--- +title: Code Freeze for 3.3 & Performance +slug: code-freeze-for-3-3-performance +url: /blog/code-freeze-for-3-3-performance/ +original_url: https://www.codenameone.com/blog/code-freeze-for-3-3-performance.html +aliases: +- /blog/code-freeze-for-3-3-performance.html +date: '2016-01-19' +author: Shai Almog +--- + +![Header Image](/blog/code-freeze-for-3-3-performance/3.3-coming-soon.jpg) + +We’ve been working feverishly to get Codename One 3.3 out of the door next week. Tomorrow morning we +will finally have the codefreeze branch for 3.3 and we’ll be able to focus on getting the docs/release in order. +The release should be on the 27th of the month and we should ideally get the plugins out of the door within the +next couple of days. + +#### Performance Update + +We’ve worked a lot on getting Android to perform nicely in the newer phones. When we launched the Android +graphics architecture was quite different than it is today so we had to make quite a few changes over the years. +Unfortunately, because of the ridiculously wide variety of devices something that performs well (or even functions) +across devices is just not technically feasible on Android. +We made a lot of improvements but they carry a heavy risk and we won’t turn them on by default on 3.3, we did +however add an option to try them dynamically. You can just invoke the call: + + + Display.getInstance().setProperty("platformHint.legacyPaint", "false"); + +This will toggle on the new Android optimizations (but have no effect elsewhere), you can flip the flag back and +forth dynamically to see the difference. Although notice that you should probably recreate the form when doing this +as some content might end up blank as a result. +Notice that while this improves our Android performance significantly on newish devices (ironically we perform +well on older devices and very new devices), this isn’t the “end all” for performance tuning on Android. We +are still working on improving performance further both on Android & iOS. This will also include revisited +tools & guides for performance optimization/tuning of your apps. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/code-freeze-for-3-4.md b/docs/website/content/blog/code-freeze-for-3-4.md new file mode 100644 index 0000000000..f46847cec8 --- /dev/null +++ b/docs/website/content/blog/code-freeze-for-3-4.md @@ -0,0 +1,42 @@ +--- +title: Code Freeze for 3.4 +slug: code-freeze-for-3-4 +url: /blog/code-freeze-for-3-4/ +original_url: https://www.codenameone.com/blog/code-freeze-for-3-4.html +aliases: +- /blog/code-freeze-for-3-4.html +date: '2016-04-25' +author: Shai Almog +--- + +![Header Image](/blog/code-freeze-for-3-4/release3.4.jpg) + +Today we are going into code freeze for Codename One 3.4 which is due one week from now, because of the +fast release cycle we don’t need more than a week of code freeze to stabilize our current release. + +The code freeze applies only to the Codename One libraries and ports as those are the parts that will be inherent +to the release. + +### How does the Code Freeze Work? + +The pieces of Codename One that are frozen are effectively the entire github repository with the exception +of the Codename One designer and JavaDoc comments. That means that we will avoid any non-critical +commits to that change anything other than the designer or docs until next Tuesday. + +Notice that plugins etc. move at their own pace and are a separate entity from the release cycle. + +We introduce a 3.4 branch into the git repository so you can reference the 3.4 version in the future. For critical +issues that must be introduced to the 3.4 release we review each commits and merge it into the 3.4 branch. +Commits will not go directly into the 3.4 branch and will instead go into the trunk where they will be cherry picked +into the branch. + +Because of this we will skip the Friday releases during the actual release phase and focus on getting 3.4 out +of the door. Once that is out we will return to our regularly scheduled release cycle. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/code-freeze-for-3-5.md b/docs/website/content/blog/code-freeze-for-3-5.md new file mode 100644 index 0000000000..ed23c91b18 --- /dev/null +++ b/docs/website/content/blog/code-freeze-for-3-5.md @@ -0,0 +1,42 @@ +--- +title: Code Freeze for 3.5 +slug: code-freeze-for-3-5 +url: /blog/code-freeze-for-3-5/ +original_url: https://www.codenameone.com/blog/code-freeze-for-3-5.html +aliases: +- /blog/code-freeze-for-3-5.html +date: '2016-07-25' +author: Shai Almog +--- + +![Header Image](/blog/code-freeze-for-3-5/codenameone35.jpg) + +Today we are going into code freeze for Codename One 3.5 which is due one week from now, because of the fast release cycle we don’t need more than a week of code freeze to stabilize our current release. + +The code freeze applies to the Codename One libraries and ports as those are the parts that are inherent to the release. + +### What Didn’t Make the Release + +We have many new features and great capabilities that we were able to introduce for 3.5. We will go into those with our release announcement. + +The biggest “miss” we have in this release is the new iOS build servers with xcode 7+. We wanted to get them out before the release but this requires more work than we initially expected to get right. We remain committed to going thru with this process and will do so after the 3.5 release. + +We didn’t finish modernizing and updating all the demos with this release. It’s disappointing but not crucial as most of the big ones are already done and the process is half way thru. + +The new peer components implementation isn’t yet ready for primetime and isn’t the default (yet). It’s still not implemented on iOS where the implementation seems to be more challenging in some regards. + +### How does the Code Freeze Work? + +The pieces of Codename One that we freeze are effectively the entire github repository except for the Codename One designer and JavaDoc comments. That means that we will avoid any non-critical commits to that change anything other than the designer or docs until next Tuesday. + +Notice that plugins etc. move at their own pace and are a separate entity from the release cycle. + +We introduce a 3.5 branch into the git repository so you can reference the 3.5 version in the future. We review commits related to critical issues and merge them into the 3.5 branch. Commits will not go directly into the 3.5 branch and will instead go into the trunk where we cherry pick them into the branch. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/code-freeze-for-3-7.md b/docs/website/content/blog/code-freeze-for-3-7.md new file mode 100644 index 0000000000..a9d1ee5a6d --- /dev/null +++ b/docs/website/content/blog/code-freeze-for-3-7.md @@ -0,0 +1,63 @@ +--- +title: Code Freeze for 3.7 +slug: code-freeze-for-3-7 +url: /blog/code-freeze-for-3-7/ +original_url: https://www.codenameone.com/blog/code-freeze-for-3-7.html +aliases: +- /blog/code-freeze-for-3-7.html +date: '2017-06-19' +author: Shai Almog +--- + +![Header Image](/blog/code-freeze-for-3-7/codenameone-3-7.jpg) + +3.7 is almost here…​ Later today we will enter the week long code freeze where only critical issues are fixed. We’ll publish the plugin release candidate for 3.7 soon and it will include some interesting new things that I haven’t discussed at all! + +I’m too busy with the new courses but I hope I’ll be able to go into details with the release announcement. + +The birthday of 3.7 will be on Tuesday June 27th…​ Up to then all new commits to git need to go thru code reviews and must match a P1 bug. + +Assuming the release candidate will become the final release all will be well, but we might need to push additional updates to fix regressions or issues so this week might include several server updates. Because of that we will skip the next two Friday releases and will push as needed. We should get back to our regular Friday updates by July 7th. + +We might release several plugin updates in the near future to iron out bugs and regressions with the release so bare with us during this tumultuous week. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **salah Alhaddabi** — June 21, 2017 at 4:51 am ([permalink](https://www.codenameone.com/blog/code-freeze-for-3-7.html#comment-23523)) + +> salah Alhaddabi says: +> +> We are all with you and support your excellent vision Shai. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-3-7.html) + + +### **Francesco Galgani** — June 21, 2017 at 5:22 pm ([permalink](https://www.codenameone.com/blog/code-freeze-for-3-7.html#comment-23561)) + +> Francesco Galgani says: +> +> I’ve just installed the 3.7 in Netbeans. +> At the moment is there any detailed announcement of the changes compared to the previous version? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-3-7.html) + + +### **Shai Almog** — June 22, 2017 at 4:24 am ([permalink](https://www.codenameone.com/blog/code-freeze-for-3-7.html#comment-23546)) + +> Shai Almog says: +> +> We will have a release announcement with itemized details on Tuesday the 27th. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-3-7.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/code-freeze-for-codename-one-7-0.md b/docs/website/content/blog/code-freeze-for-codename-one-7-0.md new file mode 100644 index 0000000000..5c64761821 --- /dev/null +++ b/docs/website/content/blog/code-freeze-for-codename-one-7-0.md @@ -0,0 +1,128 @@ +--- +title: Code Freeze for Codename One 7.0 +slug: code-freeze-for-codename-one-7-0 +url: /blog/code-freeze-for-codename-one-7-0/ +original_url: https://www.codenameone.com/blog/code-freeze-for-codename-one-7-0.html +aliases: +- /blog/code-freeze-for-codename-one-7-0.html +date: '2021-01-29' +author: Shai Almog +--- + +![Codename One 7.0 - Video](/blog/code-freeze-for-codename-one-7-0/7.0-Video-1c.jpg) + +At long last we’re entering code freeze for Codename One 7.0. This release cycle has been longer than it should have been because of many detours along the way. + +But finally if all goes according to plan, **version 7.0 should be out next Friday**. + +The code freeze won’t impact most of you as it’s mostly an artifact of our release cycle. + +We will have the regular Friday release but will only have critical reviewed commits during this week. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Javier Anton** — February 1, 2021 at 9:59 pm ([permalink](https://www.codenameone.com/blog/code-freeze-for-codename-one-7-0.html#comment-24392)) + +> Javier Anton says: +> +> I’m embarrassed to admit to how long I spend each day working with CN1. Thank you for all the effort, this project is a huge undertaking. You all deserve a gold medal for this +> +> As I begin expanding my use of CN1, I keep needing more and more to append my final native sources and rebuild. This process takes considerable time, as each finished build needs to be edited so it ships with everything else (I am mainly talking about XCode extensions and capabilities here). I have no idea how it’d work, but it would be great if this process could be automated in one way or another. I get dizzy from having to do this each time I build.. sometimes for extremely small changes (since the built sources are illegible and can’t realistically be changed after they’ve come out of the build server). Anyway, just a thought, thanks again guys +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-codename-one-7-0.html) + + +### **Shai Almog** — February 2, 2021 at 2:38 am ([permalink](https://www.codenameone.com/blog/code-freeze-for-codename-one-7-0.html#comment-24393)) + +> Shai Almog says: +> +> You can use build hints and native code to customize the project for most intents and purposes e.g. ios.add_libs allows you to add frameworks from xcode. The idea is to get a fully functional app without requiring any customization after the fact. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-codename-one-7-0.html) + + +### **Javier Anton** — February 6, 2021 at 11:33 pm ([permalink](https://www.codenameone.com/blog/code-freeze-for-codename-one-7-0.html#comment-24401)) + +> Javier Anton says: +> +> I’m still learning the ropes when it comes to XCode. In a specific example: where in my netbeans project should I put the code with a framework that contains a Share Extension (with my own code) in order for it to be picked up by the ios.add_libs build hint? Is this possible? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-codename-one-7-0.html) + + +### **Shai Almog** — February 7, 2021 at 1:58 am ([permalink](https://www.codenameone.com/blog/code-freeze-for-codename-one-7-0.html#comment-24403)) + +> Shai Almog says: +> +> I’m not familiar enough with share extensions but if you need a specific framework to be added just add it to the list in add_libs e.g. ios.add_libs=x.framework;y.framework;mylib.a +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-codename-one-7-0.html) + + +### **Javier Anton** — February 7, 2021 at 6:21 pm ([permalink](https://www.codenameone.com/blog/code-freeze-for-codename-one-7-0.html#comment-24406)) + +> Javier Anton says: +> +> I shall look into this, thanks + + +### **Francesco Galgani** — February 2, 2021 at 4:57 pm ([permalink](https://www.codenameone.com/blog/code-freeze-for-codename-one-7-0.html#comment-24394)) + +> Francesco Galgani says: +> +> I use native interfaces extensively (which is the solution to the problem pointed out by Javier Anton). In my opinion, it would be very useful to add support for all Swift libraries and create a documentation on native interfaces that is more extensive and up-to-date than the current one. Wrapping some Android or iOS SDKs in Codename One is really difficult for me, I often go by trial and error and sometimes I’m forced to give up. A practical example is this one, in which I pointed out a problem that I don’t know how to solve (wrapping requires Swift support): +> +> However, it’s not just a Swift support problem. It also takes very advanced knowledge of how Codename One works, which we simple developers don’t always have. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-codename-one-7-0.html) + + +### **Shai Almog** — February 3, 2021 at 3:13 am ([permalink](https://www.codenameone.com/blog/code-freeze-for-codename-one-7-0.html#comment-24396)) + +> Shai Almog says: +> +> We did some deep dive tutorials on that but it’s hard to go deep as the ground is constantly shifting and you end up having to teach the native platforms themselves with all the related complexity. Unfortunately, there aren’t tricks in our quiver to solve that. It’s just hard trial and error until it works with the various native platforms. Ideally if you can package stuff as a POD or dependency then you’re 90% of the way to getting it working and most things should work that way. +> The best tip is to send a build with “include native source” and build on the native platform then migrate your changes back to Codename One. This isn’t trivial but it gives you a good starting point. +> +> We have an RFE on Swift in the issue tracker if I remember correctly. I’m not sure when we’ll get to it as our issue pipeline is pretty deep and our manpower is heavily committed to some deep tasks. This is also a pretty hard task to implement and will produce a sub-par result since Swift is inherently problematic with VMs due to ARC. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-codename-one-7-0.html) + + +### **Javier Anton** — February 6, 2021 at 11:41 pm ([permalink](https://www.codenameone.com/blog/code-freeze-for-codename-one-7-0.html#comment-24402)) + +> Javier Anton says: +> +> What I meant by appending the native sources was adding Targets (Share Extensions, Notification Service/Content Extensions, etc) and modifying core files like delegate/view controller. I don’t think this can be accomplished using native interfaces please correct me if I am wrong. I also don’t know if using Targets will in some way solve your swift problem since each target can have either objc/swift and it all works together +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-codename-one-7-0.html) + + +### **Shai Almog** — February 7, 2021 at 2:03 am ([permalink](https://www.codenameone.com/blog/code-freeze-for-codename-one-7-0.html#comment-24404)) + +> Shai Almog says: +> +> You can inject sources to various files such as the delegates with build hints. If you look at the source code in git you’ll see various magical comments that generally contain the word “REPLACE” these are special comments that our build servers replace and we can give you a build hint to replace code in that area (some of these build hints are documented). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-codename-one-7-0.html) + + +### **Javier Anton** — February 7, 2021 at 6:21 pm ([permalink](https://www.codenameone.com/blog/code-freeze-for-codename-one-7-0.html#comment-24405)) + +> Javier Anton says: +> +> I know, and thanks. I still need to inject code in areas where there aren’t build hint markers as well as remove existing code. This is mostly due to the fact that I am implementing my own push, so I am probably just an outlier +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcode-freeze-for-codename-one-7-0.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/code-ranch-questions.md b/docs/website/content/blog/code-ranch-questions.md new file mode 100644 index 0000000000..5b193c65bd --- /dev/null +++ b/docs/website/content/blog/code-ranch-questions.md @@ -0,0 +1,24 @@ +--- +title: Code Ranch Questions +slug: code-ranch-questions +url: /blog/code-ranch-questions/ +original_url: https://www.codenameone.com/blog/code-ranch-questions.html +aliases: +- /blog/code-ranch-questions.html +date: '2018-08-20' +author: Shai Almog +--- + +![Header Image](/blog/code-ranch-questions/create-uber-clone-book-promo-1024.png) + +I’m answering questions in the [Code Ranch](https://coderanch.com/t/698065/mobile/Shai-Almog) this week about [Create an Uber Clone in 7 Days](https://www.amazon.com/Create-Uber-Clone-Days-mobile-ebook/dp/B07FRXZRRV/). So far I’ve had some pretty great ones, if you have a question join the conversation for a chance to win a free copy. To qualify just ask in the [Android forum](https://coderanch.com/f/93/Android) and make sure to qualify it with “Create an Uber Clone in 7 Days:” so I will notice the question. + +So far the book is doing well trending in the #2 to #3 spot for mobile development books in the kindle store. The print version isn’t selling as nicely, probably because of the huge price difference between the kindle and print book. Since the print book took far more effort, I might skip doing a print book if I go through this again. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codefreeze-4-taxi.md b/docs/website/content/blog/codefreeze-4-taxi.md new file mode 100644 index 0000000000..353113e3f2 --- /dev/null +++ b/docs/website/content/blog/codefreeze-4-taxi.md @@ -0,0 +1,46 @@ +--- +title: Codefreeze for Codename One 4.0 – Taxi +slug: codefreeze-4-taxi +url: /blog/codefreeze-4-taxi/ +original_url: https://www.codenameone.com/blog/codefreeze-4-taxi.html +aliases: +- /blog/codefreeze-4-taxi.html +date: '2018-03-12' +author: Shai Almog +--- + +![Header Image](/blog/codefreeze-4-taxi/codenameone-4-0-release-image-taxi.jpg) + +Codename One 4.0 (Taxi) will launch next week, to keep the code stable we are entering a week long code freeze. Please update your plugin installs frequently and report bugs immediately so we will have a stable release! + +We’ve added a lot of new features to 4.0 but the big things are pretty disruptive: + + * Xcode 9.2 switch + + * Update Framework + +Because both of these changes have many subtle implications we are relying on feedback from you on what’s working and what isn’t. If you run into any issue please [file the issue](http://github.com/codenameone/CodenameOne/issues/) ASAP so we can move quickly and update the release if necessary. + +During this week of code freeze we’ll try to update the documentation and prepare everything for the release. + +### Upcoming Milestones + +This is our first release in the new numbering scheme and our first code named release. + +We will branch to the 4.0 branch in our repository and every change to the branch will be cherry picked individually. + +Here are the coming releases after 4.0 (Taxi): + + * 5.0 (Social) – Scheduled for July 17th 2018 + + * 6.0 (Name Pending) – Scheduled for November 14 2018 + +You can track these milestones and the related tasks in our github project [here](https://github.com/codenameone/CodenameOne/milestones). + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codefreeze-5-social.md b/docs/website/content/blog/codefreeze-5-social.md new file mode 100644 index 0000000000..563b2340b7 --- /dev/null +++ b/docs/website/content/blog/codefreeze-5-social.md @@ -0,0 +1,46 @@ +--- +title: Codefreeze for Codename One 5.0 – Social +slug: codefreeze-5-social +url: /blog/codefreeze-5-social/ +original_url: https://www.codenameone.com/blog/codefreeze-5-social.html +aliases: +- /blog/codefreeze-5-social.html +date: '2018-09-11' +author: Shai Almog +--- + +![Header Image](/blog/codefreeze-5-social/codenameone-5-release-banner.jpg) + +Codename One 5.0 (Social) will launch next week, to keep the code stable we are entering a week long code freeze. Please update your plugin installs frequently and report bugs immediately so we will have a stable release! + +We’ve added a lot of new features to 5.0 but a few of the big things are pretty disruptive: + + * [OpenJDK Support with JDK 9, 10 & 11 support](/blog/uber-book-is-out-jdk-11.html) + + * [XIB Build Mode](/blog/no-more-ios-screenshots.html) + + * [New cloud servers](/blog/new-build-cloud.html) + +Because all of these changes have many subtle implications we are relying on feedback from you on what’s working and what isn’t. If you run into any issue please [file the issue](http://github.com/codenameone/CodenameOne/issues/) ASAP so we can move quickly and update the release if necessary. + +During this week of code freeze we’ll try to update the documentation and prepare everything for the release. + +### Upcoming Milestones + +We will branch to the 5.0 branch in our repository and every change to the branch will be cherry picked individually. + +Here are the coming releases after 5.0: + + * 6.0 (Chat) – Scheduled for February 19 2019 + + * 7.0 (Video) – Scheduled for June 12 2019 + +You can track these milestones and the related tasks in our github project [here](https://github.com/codenameone/CodenameOne/milestones). + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codefreeze-for-3-1-news.md b/docs/website/content/blog/codefreeze-for-3-1-news.md new file mode 100644 index 0000000000..80fee7e6d0 --- /dev/null +++ b/docs/website/content/blog/codefreeze-for-3-1-news.md @@ -0,0 +1,41 @@ +--- +title: Codefreeze For 3.1 & News +slug: codefreeze-for-3-1-news +url: /blog/codefreeze-for-3-1-news/ +original_url: https://www.codenameone.com/blog/codefreeze-for-3-1-news.html +aliases: +- /blog/codefreeze-for-3-1-news.html +date: '2015-07-19' +author: Shai Almog +--- + +![Header Image](/blog/codefreeze-for-3-1-news/3.1.jpg) + +We just entered code freeze preparing for the release of Codename One 3.1. This is a one week freeze that is scheduled to +end on July 28th after the release of the new version. In the next week we will only be working on critical bugs for +stability and won’t add new features. +After the release of 3.1 we will start aiming for 3.2 currently scheduled for the end of October as part of our new 3 month +release cycle. + +Our current stated plan for releases includes 3.1 for the 27th of July, 3.2 for the 27th of October and 3.3 for the 27th of January. +Assuming this keeps working out nicely we will probably keep the 3 month release cycle going for the forseeable future. There is +one major feature we wanted to release in 3.1 but couldn’t get out the door in time. On the other hand the certificate +wizard came in early and surprised us. This shows us that we can still deliver a substantive release within a 3 month cycle +without compromising. + +One of the big advantages of the short release cycle is that updating the developer guide becomes much easier. +As part of the 3.1 work we made quite a few updates to the developer guide and related documentation, it is now set to +3.1 and includes sections covering many of the new features for Codename One have been updated. + +In other news we updated the Facebook integration to include support for inviting friends which will enable some +common use cases of interacting with Facebook friends. We fixed a rare crash with the new VM relating to an +edge case usage of the dup2x bytecode. We’ll update the plugins for the various IDE’s later in the week in preparation +for the release. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codefreeze-for-3-8.md b/docs/website/content/blog/codefreeze-for-3-8.md new file mode 100644 index 0000000000..5e286279e5 --- /dev/null +++ b/docs/website/content/blog/codefreeze-for-3-8.md @@ -0,0 +1,102 @@ +--- +title: Codefreeze for 3.8 +slug: codefreeze-for-3-8 +url: /blog/codefreeze-for-3-8/ +original_url: https://www.codenameone.com/blog/codefreeze-for-3-8.html +aliases: +- /blog/codefreeze-for-3-8.html +date: '2017-11-06' +author: Shai Almog +--- + +![Header Image](/blog/codefreeze-for-3-8/codenameone-3-8.jpg) + +Codename One 3.8 should land one week from now and from later today we are effectively in code freeze. Please update to the release candidate of 3.8 tomorrow morning to help us track some last minute bugs and regressions. As is usually our process we will release updates as necessary with code reviews and next week we won’t have the usual set of releases as we’ll take some time off. + +We will branch to the 3.8 branch in our repository and every change to the branch will be cherry picked individually. + +During this week of code freeze we’ll try to update the documentation and prepare everything for the release. There are many important features in this release but as is our approach in recent releases the emphasis is strongly on refinement. If you run into any issue please [file the issue](http://github.com/codenameone/CodenameOne/issues/) ASAP so we can move quickly and update the release if necessary. + +### Upcoming Milestones + +As you might recall we announced a switch to major version milestones which means the next release is 4.0. Here are the coming releases: + + * 4.0 – Scheduled for March 6th 2018 + + * 5.0 – Scheduled for July 17th 2018 + + * 6.0 – Scheduled for November 14 2018 + +You can track these milestones and the related tasks in our github project [here](https://github.com/codenameone/CodenameOne/milestones). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — November 7, 2017 at 11:21 am ([permalink](https://www.codenameone.com/blog/codefreeze-for-3-8.html#comment-23841)) + +> Francesco Galgani says: +> +> So I suppose that the manual (developer guide) for the 3.8 release will be ready soon. +> Can you publish it not only on Amazon, but also in other book resellers, please? I have problems with Amazon. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodefreeze-for-3-8.html) + + +### **Shai Almog** — November 8, 2017 at 6:47 am ([permalink](https://www.codenameone.com/blog/codefreeze-for-3-8.html#comment-21528)) + +> Shai Almog says: +> +> Yes we will push out the 3.8 manual hopefully next week. +> We won’t publish it elsewhere since the book is a print on demand book (POD) so Amazon literally does the printing of the book. Submitting to POD is a bit of a painful process so I don’t think we’ll go through other POD shops as well. +> The PDF is still available and would be in sync with the book so if Amazon isn’t an option you can always print that as a last resort. It’s not ideal but can work. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodefreeze-for-3-8.html) + + +### **ayad_alssady** — February 20, 2018 at 4:34 pm ([permalink](https://www.codenameone.com/blog/codefreeze-for-3-8.html#comment-23640)) + +> ayad_alssady says: +> +> please want to help me in the example how to add a second hand to a widget analog clock application can you give me the code for it +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodefreeze-for-3-8.html) + + +### **Shai Almog** — February 21, 2018 at 5:27 am ([permalink](https://www.codenameone.com/blog/codefreeze-for-3-8.html#comment-23803)) + +> Shai Almog says: +> +> I don’t understand how this relates to this post? +> It’s the same as the minutes hand only faster. I don’t understand the difficulty? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodefreeze-for-3-8.html) + + +### **ayad_alssady** — February 21, 2018 at 7:35 am ([permalink](https://www.codenameone.com/blog/codefreeze-for-3-8.html#comment-23843)) + +> ayad_alssady says: +> +> I mean this second hand in the widget in android studio +> [https://uploads.disquscdn.c…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodefreeze-for-3-8.html) + + +### **Shai Almog** — February 22, 2018 at 8:43 am ([permalink](https://www.codenameone.com/blog/codefreeze-for-3-8.html#comment-23861)) + +> Shai Almog says: +> +> I understood that. I don’t understand what’s the problem with our sample code: [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodefreeze-for-3-8.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codefreeze-for-chat.md b/docs/website/content/blog/codefreeze-for-chat.md new file mode 100644 index 0000000000..d26c0921ed --- /dev/null +++ b/docs/website/content/blog/codefreeze-for-chat.md @@ -0,0 +1,27 @@ +--- +title: Codefreeze for Chat (Codename One 6.0) +slug: codefreeze-for-chat +url: /blog/codefreeze-for-chat/ +original_url: https://www.codenameone.com/blog/codefreeze-for-chat.html +aliases: +- /blog/codefreeze-for-chat.html +date: '2019-02-19' +author: Shai Almog +--- + +![Header Image](/blog/codefreeze-for-chat/codenameone-6-release-banner.jpg) + +We’re entering code freeze later tonight which means no further commits will be made. After the code freeze only reviewed commits can be cherry picked. Only critical bugs will be fixed at that point. +We will push out a new plugin update and tools tomorrow morning. They will be labeled 6.0 and serve as release candidates. If there are issues we’ll push out further updates during the week. + +Once the release is made we’ll skip the next Friday release as is our practice with the first Friday after a release. + +We [closed 96 issues](https://github.com/codenameone/CodenameOne/milestone/13) as part of this release so far. Some things proved problematic and were postponed to [version 7.0](https://github.com/codenameone/CodenameOne/milestone/14) hopefully we’ll catch up to most of them by then. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-3-0-now-live.md b/docs/website/content/blog/codename-one-3-0-now-live.md new file mode 100644 index 0000000000..8e753bbe3b --- /dev/null +++ b/docs/website/content/blog/codename-one-3-0-now-live.md @@ -0,0 +1,213 @@ +--- +title: Codename One 3.0 Now Live & Special Offer! +slug: codename-one-3-0-now-live +url: /blog/codename-one-3-0-now-live/ +original_url: https://www.codenameone.com/blog/codename-one-3-0-now-live.html +aliases: +- /blog/codename-one-3-0-now-live.html +date: '2015-04-26' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-3-0-now-live/CodenameOne-Horizontal.png) + +We are thrilled to announce the immediate availability of Codename One 3.0! +To celebrate this release we are giving away a **$100 rebate discount** for annual pro +subscriptions and **$300 rebate discount** for annual enterprise subscriptions. +All you need to do to get this rebate is [signup](http://www.codenameone.com/pricing.html) for an annual subscription and the appropriate sum will +be refunded within 24 hours thru PayPal. This offer is valid before June 1st 2015. +You can check out the press release and full announcement [here](/files/pr/CodenameOne3.0PressRelease.pdf). + +**Go a head and update your Plugin now to get the new Release.** + +### Highlights Of The Release – Click For Details + +____New iOS VM + +When Codename One debuted we used XMLVM as the underlying iOS virtual +machine abstraction. XMLVM is an excellent product but its unmaintained and its goals are too different from the +goals of Codename One. The new VM includes some features that would be remarkably hard to achieve with XMLVM +such as: proper stack traces, faster builds (2x overall!), smaller code size, concurrent GC, deep OS binding (String – NSString relationship) etc. +Read more about this work on [the announcement blog](/blog/new-codename-one-ios-vm-is-now-the-default.html). + +____JavaScript build target (technology preview) + +Allows compiling Codename One applications to JavaScript client side webapps +without server side code. Notice that this support includes threading support. +Notice that this feature will be restricted to enterprise developers once it enters beta. +The Java VM work is based on [TeaVM](http://teavm.org/) an OSS Java-JavaScript VM. + +Read more about this work in [this blog post](/blog/javascript-port.html). + +____Charts API + +The charts API supports drawing a wide range of charts such as bar, pie, line etc. It supports animating +charts and is based on the aChartEngine Android API. +Read more about this work on [Steve’s blog post](/blog/codename-one-charts.html). + +____New Demos + + * [Property Cross](/blog/propertycross-demo.html) – Browse properties for sale in the UK using a JSON webservice. Shows off JSON webservices, InfiniteScroll, URLImage etc. + * [Dr Sbaitso](/blog/dr-sbaitso.html) – Demonstrates an AI bubble chat interface, includes text to speech using native interface and more. + * [Photoshare](/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube) – A simple social networking app that allows sharing photos + * [Charts](/blog/codename-one-charts) – Demonstrates all chart types + * [Geoviz](/blog/geo-visualization-library.html) – Performs statistic analysis over US population based on locale specific data + * [Flickr](/blog/cats-in-toolbars.html) – Demo for the Toolbar class showing special title area effects + +____New Themes + +New beautiful and functional themes are now available through the plugins and +the designer tool. + +____Toolbar API + +More advanced and highly customizable API for handling +the title area. It allows adding search to the title, animating its appearance/folding, placing commands +arbitrarily and using the side menu. +Read more about this work on [this blog post](/blog/cats-in-toolbars.html). + +____URLImage + +Simplified image download to an icon or preview, +that allows to implicitly apply special effects to said image (e.g. round corners, scaling etc.). +Read more about this work on [this blog post](/blog/image-from-url-made-easy.html). + +____Built demos into the Eclipse/NetBeans Plugins + +The main Codename One demos are now built-into the plugin so you can try them immediately without +fixing classpaths and without downloading additional software. + +____New Android graphics pipeline + +We rewrote the graphics pipeline on Android to work better in Android 4.x+ and use hardware acceleration +where applicable. This new pipeline also includes support for the Shape & transform API’s. +Read more about this work on [this blog post](/blog/new-android-pipeline-fixes.html). + +____Regular expression and validation support + +We added a new regular expression package and a new validation framework that simplifies +error highlighting for input. As part of that work we also presented a rudimentary masked +input UI. +Read more about this work on [this blog post](/blog/validation-regex-masking.html). + +____High DPI Image Support + +There are 3 new DPI levels in Codename One all of which are now supported by the designer: +DENSITY_560, DENSITY_2HD & DENSITY_4K. + +____Support for opening HTML files with hierarchies & Tar support + +The builtin HTML support was improved by providing a way to open a hierarchy of files and not just +a self contained HTML file. As part of this improvement we also added support to the tar file format. +Read more about this work on [this blog post](/blog/html-hierarchy-release-plan-teavm.html). + +____New Morph & Flip Transitions + +The [morph transition](/blog/mighty-morphing-components.html) was inspired by the Material design UI, converting a component on one form to +a component on another form. The [flip transition](/blog/easy-demos-flip-more.html) provides an impressive 3d effect thats trivial to apply +to any form or transition. + +____InteractionDialog + +A new “modless” dialog that can “float” on top of the +UI using the layered pane capability of the parent form +Read more about this work on [this blog post](/blog/not-a-dialog-again.html). + +____Significantly enhanced developer guide + +We redid the developer guide from the ground up converting +it to asciidoc and integrating it into the website in a more fluent way. We increased its breadth by over +50%. +Check it our [here](/manual/) or download the [pdf](/files/developer-guide.pdf). + +____iOS Beta Test Support (testflight) + +Apple introduced a new way to test mobile applications for up to 1000 beta testers based on the testflight +framework (but not to be confused with the old testflightapp.com product). We now support distributing +apps via this process for pro users. +Read more about this work on [this blog post](/blog/location-ios-beta-testing-better-input.html). + +____MiG layout support + +MiG layout is one of the popular cross platform Java layout managers that works across FX, Swing, AWT +and now on Codename One as well… +Read more about this work on [this blog post](/blog/location-ios-beta-testing-better-input.html). + +____Facebook improvements such as publish support & version 2.0 API + +Facebook made a lot of changes to its API such as requiring a special +[publish permission](/blog/facebook-publish-android-localization.html) +and migrating graph calls to version 2.0. Both are now integrated into Codename One. + +____Added webservice wizard to simplify client-server calls + +The +[webservice wizard](/how-do-i---access-remote-webservices-perform-operations-on-the-server.html) allows us to +generate RPC calls to the server including servlet and client stubs. +Read more about this work on [this blog post](/blog/webservice-wizard.html). + +____Support for badging the native OS icon on iOS + +We now support updating and setting a badge on an app icons in iOS devices. +Read more about this work on [this blog post](/blog/badges.html). + +____TCP socket support + +We finally added support for TCP sockets into Codename One. +Read more about this work on [this blog post](/blog/sockets-multiline-trees.html). + +____Advanced keyboard input in iOS that doesn’t fold implicitly + +This is an implementation of a feature that was [requested](https://code.google.com/p/codenameone/issues/detail?id=361) +quite a while back. Historically, when moving from one text field to the next the VKB would fold and reopen. We now allow you to seamlessly +move between input fields. + +You can also read the far more detailed list of release notes [here](/codenameone-3-0-release-notes.html). + +One of the things we are announcing today is a switch to faster release cycles, we already announced the +next two release dates which will probably map to versions 3.1 and 3.2 respectively: July 27th and October 27 2015. +Notice that the dates are 3 months apart allowing us to make releases much faster and keep Codename One +stable in shorter iterations. This effectively means that +[versioned builds](/how-do-i---get-repeatable-builds-build-against-a-consistent-version-of-codename-one-use-the-versioning-feature.html) +will become a more viable feature. It also means that the feature list for every release will be very volatile +and we won’t announce them until the release is out of the door. + +### Warning For Users Of The Old VM (XMLVM) + +If you are still using the build flag ios.newVM=false we **strongly** suggest you stop right now! +Even if you don’t need appstore submission and aren’t worried about the impending July cutoff date for the old +VM you would still need to migrate! + +Apple broke xcode 5.x builds with its new Mac OS release Yosemite, this has been broken for a while and it +seems that Apple has no intention of fixing this. Unfortunately Apple has a tendency of tying xcode upgrades and +OS upgrades together, our build servers are still running Mavericks (the previous OS X release) and we have +no intention of upgrading them right now. However, if we find ourselves in need of a new server or if Apple +forces us to use a new version of xcode (and thus a newer version of Mac OS) we would be forced to upgrade +the servers. +Such an upgrade will make all builds targeting XMLVM fail! + +The correct thing to do is move to the new VM which we are actively supporting as much as possible, we suggest +you do it now rather than hastily at a later date. It provides many advantages including stack traces & a +superior gc. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **manezi** — April 30, 2015 at 12:22 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-0-now-live.html#comment-22103)) + +> manezi says: +> +> Fantastic news. Well done to the CN1 team! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-0-now-live.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-3-1-easier-iteration.md b/docs/website/content/blog/codename-one-3-1-easier-iteration.md new file mode 100644 index 0000000000..e06a35bc39 --- /dev/null +++ b/docs/website/content/blog/codename-one-3-1-easier-iteration.md @@ -0,0 +1,54 @@ +--- +title: Codename One 3.1 & Easier Iteration +slug: codename-one-3-1-easier-iteration +url: /blog/codename-one-3-1-easier-iteration/ +original_url: https://www.codenameone.com/blog/codename-one-3-1-easier-iteration.html +aliases: +- /blog/codename-one-3-1-easier-iteration.html +date: '2015-07-12' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-3-1-easier-iteration/3.1.jpg) + +Its been a busy month and getting busier by the moment, we are preparing for App Engines suspension of +its blobstore service which will be coming around soon. This effectively means older crash report email +functionality will be stopped for older apps (just rebuild the app for the emails to work again). +We are also getting ready for Codename One 3.1 which we have tentatively scheduled for July 27th. This +release will include a weeks worth of code freeze and will be +the first of our new policy for faster release schedules. + +Some features we wanted to make it will have to go in to 3.2 but overall we are pretty thrilled with the shorter +release cycle which makes a whole lot of sense in the mobile industry where things change so frequently. +We will release an updated plugin tomorrow morning which should include a lot of the newer features for 3.1. + +#### Easier Iteration on Containers + +I often write code that needs to iterate over the components of a container in the form: + + + int count = cont.getComponentCount(); + for(int iter = 0 ; iter < count ; iter++) { + Component c = cont.getComponentAt(iter); + // do something with c + } + +This is tedious and annoying, so with the latest version of Codename One it implements the `Iterable` interface +which allows this instead: + + + for(Component c : cont) { + // do something with c + } + +Which is obviously easier, its not necessarily as efficient but its easier to write. These are the sort of features +we should add into Codename One all over e.g. we just fixed `Element` from the XML parsing +code to allow iteration over its children in a similar way. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-3-1-now-live.md b/docs/website/content/blog/codename-one-3-1-now-live.md new file mode 100644 index 0000000000..74a9ddd2be --- /dev/null +++ b/docs/website/content/blog/codename-one-3-1-now-live.md @@ -0,0 +1,83 @@ +--- +title: Codename One 3.1 Now Live +slug: codename-one-3-1-now-live +url: /blog/codename-one-3-1-now-live/ +original_url: https://www.codenameone.com/blog/codename-one-3-1-now-live.html +aliases: +- /blog/codename-one-3-1-now-live.html +date: '2015-07-26' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-3-1-now-live/CodenameOne-Horizontal.png) + +We are thrilled to announce the immediate availability of Codename One 3.1! +Version 3.1 is the first release in our fast pace release cycle of 4 releases per year. It brings stability, bug +fixes and great new features to the table. The biggest highlights of this release are support for Java 8 and simplified +certificate generation for iOS. Check out the list below for more details. + +### Highlights Of The Release – Click For Details + +____Java 8 Language Features + +Support for Java 8 features such as Lambdas, try with resources etc. This is a beta +grade feature but is showing great promise so far. +Read more about this work in [this blog post](/blog/java-8-support.html). + +____iOS Certificate Wizard + +Simple generation of certificates and provisioning for itunes +without a Mac using a wizard interface. +Read more about this work in [this blog post](/blog/ios-certificate-wizard.html). + +____Authentication Framework + +Provides the ability to signin to various services in a generic way including builtin support for Google, Facebook and +generic oAuth 2.0 services. +Read more about this work in [this blog post](/blog/sign-in-with.html). + +____Font Icons + +Support for using icon fonts to represent images in the UI thus reducing the reliance on multi-images. +Read more about this work in [this blog post](/blog/icon-fonts-oldvm-swan-song.html). + +____Better Crash Reporting + +As part of migrating away from Google App Engine we shifted crash reports to use new servers which make +them far more usable by embedding the logs directly into the email body. +Read more about this work in [this blog post](/blog/migrating-away-from-app-engine.html). + +You can also read the far more detailed list of release notes [here](/codenameone-3-1-release-notes.html). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — July 27, 2015 at 4:22 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-1-now-live.html#comment-21485)) + +> Chidiebere Okwudire says: +> +> Well done guys! +> +> BTW, the ‘detailed list of release notes’ link is broken. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-1-now-live.html) + + +### **Shai Almog** — July 27, 2015 at 4:30 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-1-now-live.html#comment-22412)) + +> Shai Almog says: +> +> Thanks, its updated now. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-1-now-live.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-3-2-now-live.md b/docs/website/content/blog/codename-one-3-2-now-live.md new file mode 100644 index 0000000000..80d048b059 --- /dev/null +++ b/docs/website/content/blog/codename-one-3-2-now-live.md @@ -0,0 +1,289 @@ +--- +title: Codename One 3.2 Now Live +slug: codename-one-3-2-now-live +url: /blog/codename-one-3-2-now-live/ +original_url: https://www.codenameone.com/blog/codename-one-3-2-now-live.html +aliases: +- /blog/codename-one-3-2-now-live.html +date: '2015-10-26' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-3-2-now-live/CodenameOne-Horizontal.png) + +We are thrilled to announce the immediate availability of Codename One 3.2! +Version 3.2 sets the pace for many upcoming features & migration processes such as the +new cloud infrastructure for push servers, modernized GUI builder etc. +Codename One 3.3 is currently scheduled for January 27th 2016 and should continue the trend of iterative changes +that form a larger platform evolution arch. + +### Highlights Of The Release – Click For Details + +____New GUI Builder (technology preview) + +The new GUI builder is a big departure from our existing +designer tool. This tool is now in “technology preview” status meaning that its not quite ready for +prime time but we want feedback on its direction and issues. +Read more about this work in [this blog post](/blog/new-gui-builder.html). + +____Local Notifications on iOS and Android + +Local notifications are similar to push notifications, except that they are initiated locally by the app, +rather than remotely. They are useful for communicating information to the user while the app is running in the background, since they +manifest themselves as pop-up notifications on supported devices. +Read more about this work in [this blog post](/blog/local-notifications.html). + +____Introduced New Push Server Architecture + +We completely overhauled the way Codename One handles push services +and added several long time RFE’s to the mix. +Read more about this work in [this blog post](/blog/new-push-servers.html). + +____Added Ability for cn1libs To Include Build Hints + +cn1libs now include the ability to include build hints thus +integrate more seamlessly without complex integration instructions. +Read more about this work in [this blog post](/blog/deprecations-simplified-cn1lib-installs-theme-layering.html). + +____Improved iOS/Android Rendering Speed + +Thanks to a community contribution we took a deep look at the rendering +code and are using faster code for tiling/string rendering. +Read more about this work in [this github pull request](https://github.com/codenameone/CodenameOne/pull/1580). + +____Added A Permanent Side Menu Option + +The Toolbar API has really picked up, in order to make it more useful for Tablets +we added the ability to keep the SideMenuBar that’s builtin to it always on. +Read more about this work in [this blog post](/blog/permanent-sidemenu-getAllStyles-scrollbar-and-more.html). + +____Get All Styles – Simplified Handcoding Theme Elements + +getAllStyles() allows writing code that is more concise to perform an operation on multiple +style objects at once. +Read more about this work in [this blog post](/blog/permanent-sidemenu-getAllStyles-scrollbar-and-more.html). + +____Added Support For Facebooks “Invite A Friend” + +New integration for Facebooks “invite a friend” feature that simplifies +viral marketing for your app. +Read more about this work in [this blog post](/blog/invite-friends-websockets-windows-phone-more.html). + +____Terse Syntax For Building UI’s + +A shorter syntax for adding components and labels into the UI resulting in less code for the same functionality. +Read more about this work in [this blog post](/blog/terse-syntax-migration-wizard-more.html). + +____Java 8 Language Features are now on by default + +We fixed many things in this implementation over the past +three months and feel confident enough to switch this into the default. +Read more about this work in [this blog post](/blog/java-8-support.html). + +You can also read the far more detailed list of release notes [here](/codenameone-3-2-release-notes.html). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Diamond** — October 27, 2015 at 11:52 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22472)) + +> Diamond says: +> +> Thank you guys for the hardwork, +> +> My build always fail whenever I send a build using 1.8, I got a message that codenameone supports up to 1.7 java version… Does the build server support 1.8 now? +> +> And may I ask if “background process while app is not running” would be implemented anytime soon? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Shai Almog** — October 28, 2015 at 3:35 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22195)) + +> Shai Almog says: +> +> You need to explicitly use the Java 8 support either by migrating your project to a Java 8 project type or creating a new project. Our server code converts Java 8 bytecode down to Java 5 making this seamless to our servers. +> +> Background processes is something we slated and discussed for 3.2 and worked on a lot. The end result was just background notifications which IMO is the least important of the bunch. Hopefully this will land sooner rather than later. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Diamond** — October 28, 2015 at 4:17 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22487)) + +> Diamond says: +> +> Hi, +> +> How do I add MultiImages or create UIIDs in the new GUI Builder. +> +> Can we have a double click function on components to open their properties please. +> +> Dragging components crashes the Gui Builder sometimes. +> +> When I delete component, it doesn’t disappear from the tree and if I try to delete it again, the Gui Builder crashes. +> +> When I select a Container that has one component inside, I got properties of the component and not the container itself. +> +> Most of this stuff happens randomly. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Shai Almog** — October 28, 2015 at 9:47 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22180)) + +> Shai Almog says: +> +> Hi, +> are you sure you are building with the right account? It should be logged to the console. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Gerben** — October 28, 2015 at 9:49 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-21940)) + +> Gerben says: +> +> Turned out we had paypal issues and our account was terminated or something like that at the exact moment I installed 3.2. But is was unrelated. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Shai Almog** — October 28, 2015 at 9:55 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22242)) + +> Shai Almog says: +> +> Hi, +> adding multi-images is part of the theme which is a separate feature altogether. You need to still do that with the old designer and it will be accessible then. The same is true for creating/manipulating UIID’s. We’ll replace the theme generating functionality in the old designer using a different tool, it was a mistake mixing everything into a single tool. +> +> Single clicking a component in the UI opens its properties on the left side. If you pick it from the tree then it will be selected as you change the tabs. Notice that properties are now split into “Basic”, “Advanced” & “Events” (at the bottom of the tab). There is also a separate tab to control layout. +> +> If you get crashes or errors a log would be nice, we will add some better crash logging for the next update and hopefully start fixing these bugs quickly. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Tom Arn** — October 30, 2015 at 10:03 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22266)) + +> Tom Arn says: +> +> Is the source code of the new gui builder already available for download? +> Best regards +> Tom +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **ahmed** — October 31, 2015 at 3:52 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22386)) + +> ahmed says: +> +> The latest version i get in intellij is 3.1 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Shai Almog** — October 31, 2015 at 4:16 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22396)) + +> Shai Almog says: +> +> Our plugins aren’t open source and we are looking at the new GUI builder as a part of the plugin so at this time we don’t plan to open source it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Shai Almog** — October 31, 2015 at 4:17 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22403)) + +> Shai Almog says: +> +> We are working on a partial rewrite of the IntelliJ plugin, this is taking some time. +> Most features of 3.2 are available on IntelliJ via a library update. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Yaakov Gesher** — November 10, 2015 at 10:07 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22393)) + +> Yaakov Gesher says: +> +> After upgrading to 3.2, using the old GUI Builder, every time I make a change in a form I get a little popup saying “GUI Builder error – undoing”, but it doesn’t actually undo the changes made. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Shai Almog** — November 11, 2015 at 4:53 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22368)) + +> Shai Almog says: +> +> Can you run the GUI builder from command line and get the logged output when you get that error? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Yaakov Gesher** — November 11, 2015 at 7:51 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22455)) + +> Yaakov Gesher says: +> +> What’s the command I use for that? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Shai Almog** — November 12, 2015 at 3:09 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-21498)) + +> Shai Almog says: +> +> java -jar ~/.codenameone/designer_1.jar +> ~ is the home directory if you are doing this in Windows and you would naturally need to reverse the slashes. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Yaakov Gesher** — November 14, 2015 at 9:16 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-21540)) + +> Yaakov Gesher says: +> +> I’ll email you the stack trace. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Shai Almog** — November 15, 2015 at 4:08 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-22548)) + +> Shai Almog says: +> +> I see the issue but I don’t think its a regression since this is pretty old code. Did you change something with the TableLayout in that hierarchy? +> Can you change the column count to be larger or is this inaccessible in the GUI? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Yaakov Gesher** — November 21, 2015 at 8:48 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-24200)) + +> Yaakov Gesher says: +> +> Yeah, I realized later that I was adding components beyond the TableLayout’s defined row count. But shouldn’t there be a more user-friendly error message? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + + +### **Shai Almog** — November 22, 2015 at 4:37 am ([permalink](https://www.codenameone.com/blog/codename-one-3-2-now-live.html#comment-21548)) + +> Shai Almog says: +> +> It auto increments the row. This is a bug that we fixed. +> +> That’s just a workaround until we provide a new version of the designer. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-2-now-live.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-3-3-now-live.md b/docs/website/content/blog/codename-one-3-3-now-live.md new file mode 100644 index 0000000000..bd4ee1eab8 --- /dev/null +++ b/docs/website/content/blog/codename-one-3-3-now-live.md @@ -0,0 +1,195 @@ +--- +title: Codename One 3.3 Now Live +slug: codename-one-3-3-now-live +url: /blog/codename-one-3-3-now-live/ +original_url: https://www.codenameone.com/blog/codename-one-3-3-now-live.html +aliases: +- /blog/codename-one-3-3-now-live.html +date: '2016-01-26' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-3-3-now-live/codenameone3.3-release.jpg) + +We are thrilled to announce the immediate availability of Codename One 3.3! +Version 3.3 was tumultuous, we made a lot of earth shattering changes to performance, animations, fonts +and many other things. As a result we have a ground-breaking release that requires +a step back. +With 3.4 we want to tone down on the “big ticket changes” and work heavily on product refinement. We are already +hard at work updating our docs and refining our general process.. +In 3.3 we focused a lot on the open source aspect of Codename One which is something we neglected +to some extent in the past. We intend to keep pushing towards more transparency and community involvement +as the project grows. +Codename One 3.4 is currently scheduled for May 3rd 2016. Its chief goals are: Performance, Platform fidelity, +Documentation & ease of use. + +### Highlights Of The Release – Click For Details + +____Faster rendering of backgrounds & Labels + +Up until now the logic for rendering the background of the component +resided entirely within Component.java & DefaultLookAndFeel.java. +This allowed for a simple rendering logic that is implemented in a single place, however it didn’t allow us +to deeply optimize some operations in a platform specific way. We moved the rendering into +CodenameOneImplementation.java which allowed us to override the logic both on Android & iOS +to deliver native grade performance on any device. +On iOS this has been a strait forward change where most of the low level logic is now written using +very efficient C code. On Android the pipeline complexity is far greater, but thanks to this approach +we were able to reuse many system resources and reduce JANK significantly in applications. This +work is still ongoing but the bit effort has been implemented. +This is probably the biggest piece of multiple changes that went into this release including fast tiling +support, better font/string texture caching, Container API optimizations etc. +Read more about this work in [this blog post](/blog/code-freeze-for-3.3-performance.html). + +____Animation Manager, Title Animations & Style Animations + +We rewrote the animation logic in Codename One for 3.3. +This broke some backwards compatibility but this was for a good cause as we now have a central class +that manages all animation events going forward. This means that you should no longer get odd +exceptions when using many animations in sequence. +As part of this enhancement we also added new animation types such as title scroll animation and the +ability to animate a style object UIID. +Read more about this work in [this blog post](/blog/new-animation-manager.html). + +____“Remastered” Documentation (ongoing) + +We are redoing a lot of the Codename One documentation from scratch with +Codename One 3.3. This is ongoing and we barely just started but the new documentation is far more readable, +detailed and clear. Moving forward we are confident that our developer guide, JavaDocs & videos will be in a +league of their own! +Read more about this work in [this blog post](/blog/wiki-parparvm-performance-actionevent-type.html). + +____Material Design Icons + +FontImage has been around for a while but up until now +we didn’t use it to its full extent. It required getting an icon font, configuring it and we just skipped it +for some cases. +With 3.3 we integrated the material design icon font which makes adding flat icons to your application +remarkably simple! +Read more about this work in [this blog post](/blog/material-icons-background-music-geofencing-gradle.html). + +____Media Playback & Geo Fencing in the Background + +We continued the background process trend with +3.3 as we enabled both geofencing (to track device location in the background) and media +playback in the background. +Read more about this work in [this blog post](/blog/material-icons-background-music-geofencing-gradle.html). + +____PhoneGap/Cordova Compatibility + +Codename One always supported embedding +HTML & JavaScript but it didn’t support embedding things such as the Cordova/PhoneGap API’s. +With the new open source project we announced we can now convert many Cordova/PhoneGap apps to +Codename One apps and deliver quite a few compelling advantages. +Read more about this work in [this blog post](/blog/phonegap-cordova-compatibility-for-codename-one.html). + +____New hello world project & icon + +A major focus of this release was making Codename One useful and +attractive right out of the box. As part of that work we replaced the default icon, redid the hello world app to a +more impressive (yet simple) demo and updated the default fonts. +Read more about this work in [this blog post](/blog/good-looking-by-default-native-fonts-simulator-detection-more.html). + +____New Simplified Native Fonts + +Fonts were a difficult subject prior to 3.3. You could either use the +portable but ugly system fonts, or go with the gorgeous but flaky TTF fonts. Both don’t make sense when Android +ships with the great Roboto font and iOS ships with the gorgeous Helvetica Neue font. +We now have support for a new font notation with the native: prefix. This notation (supported by the Designer), +allows us to leverage the existing native fonts of the device which look both native and gorgeous. +Read more about this work in [this blog post](/blog/good-looking-by-default-native-fonts-simulator-detection-more.html). + +____Terse syntax enhancements + +In 3.2 we started moving towards terse syntax for container hierarchy +construction and with 3.3 we brought that to fruition. We added methods such as an add method that accepts an +image. We added factory encloseIn methods to almost all of the layout managers, we added form constructors +that accept layout managers and much more! + +Read more about this work in [this blog post](/blog/properties-continued-terseness.html). + +____ParparVM Performance & Open Source + +Our iOS VM has been open source from the start but we didn’t encourage its +usage outside of Codename One. This changed with 3.3 and we are actively promoting the ParparVM OpenSource +project. +Unrelated to that we made a lot of performance improvements to the core VM translation logic, it should be very +competitive in terms of generated code to pretty much everything else on the market. Especially with API calls as +our entire API is hand-coded and highly optimized. +Read more about this work in [this blog post](/blog/parparvm-spreads-its-wings.html). + +____Properties file format support + +We didn’t have support for Java venerable Properties file format before +3.3. Surprisingly developers didn’t really complain about that ommission as we support XML, CSV & JSON. +Now we can add Properties to that list! +Read more about this work in [this blog post](/blog/properties-continued-terseness.html). + +____Ending Support for the codescan API + +3.3 will be the last release that includes an implementation of the codescan +API for QR code/barcode reading. We will remove this API completely and we ask users to migrate their code to +use the new [codescan cn1lib](https://github.com/codenameone/cn1-codescan/). When we initially +introduced this API we didn’t have support for cn1libs and integrated this into the core directly. +Read more about this work in [this blog post](/blog/video-new-defaults-barcode-qrcode-changes.html). + +You can also read the far more detailed list of release notes [here](/codenameone-3-3-release-notes.html). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — January 27, 2016 at 11:50 am ([permalink](https://www.codenameone.com/blog/codename-one-3-3-now-live.html#comment-21615)) + +> Chidiebere Okwudire says: +> +> Cheers guys! Well done!! +> +> Something is obviously missing: An update on the new GUI builder which should have entered beta with release 3.3. What’s the status and why isn’t it mentioned in the feature list above? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-3-now-live.html) + + +### **Shai Almog** — January 27, 2016 at 12:26 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-3-now-live.html#comment-22666)) + +> Shai Almog says: +> +> Thanks! +> +> We thought about this quite a bit and chose not to emphasis that with this release even though we’ve done a lot of work on the GUI builder we still don’t feel its ready for beta. The UI/UX still isn’t perfect and the tutorials aren’t even remotely close to done. +> +> We intended to do the finishing touches during the late part of 3.3’s release cycle but then we got delayed with regressions/fixes and are now delayed due to the documentation overhaul work. So we just didn’t get around to working on the GUI builder full time. +> +> I think that once we change the documentation/videos to use the new GUI builder people will start using it and will start filing issues. This will bring it to beta-status thru inertia during the 3.3 lifespan. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-3-now-live.html) + + +### **Chidiebere Okwudire** — January 27, 2016 at 12:36 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-3-now-live.html#comment-22699)) + +> Chidiebere Okwudire says: +> +> Clear and probably a good choice. +> +> I tried creating a new project with the new GUI builder last week and after a few crashes and unclarity of how to do simple things that I can easily do with the old builder (e.g. setting components to parts of a border layout), I quit and reverted back to the old GUI builder. I’ll stick with that till further notice. I also saw a button for converting an existing project to a new GUI builder project so I guess when it’s ready, I’ll be able to migrate away from the huge state machine class. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-3-now-live.html) + + +### **Shai Almog** — January 27, 2016 at 12:48 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-3-now-live.html#comment-22637)) + +> Shai Almog says: +> +> Yes the migration wizard is already there. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-3-now-live.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-3-4-now-live.md b/docs/website/content/blog/codename-one-3-4-now-live.md new file mode 100644 index 0000000000..23249ec6ed --- /dev/null +++ b/docs/website/content/blog/codename-one-3-4-now-live.md @@ -0,0 +1,150 @@ +--- +title: Codename One 3.4 Now Live +slug: codename-one-3-4-now-live +url: /blog/codename-one-3-4-now-live/ +original_url: https://www.codenameone.com/blog/codename-one-3-4-now-live.html +aliases: +- /blog/codename-one-3-4-now-live.html +date: '2016-05-02' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-3-4-now-live/release3.4.jpg) + +We are thrilled to announce the immediate availability of Codename One 3.4! + +Version 3.4 brings with it refinement and stability as its core features, this is a trend that we are very pleased with +and intend to carry on to version 3.5. + +### Highlights of this Release + + * **Rewritten documentation** – the [developer guide](https://www.codenameone.com/manual/) was +[written from the ground up](https://www.codenameone.com/files/developer-guide.pdf) +and the [JavaDocs](https://www.codenameone.com/javadoc/) were significantly improved + + * **IntelliJ IDEA Plugin rewrite** – the new [IntelliJ IDEA support](/blog/a-new-idea.html) is +as good as the NetBeans plugin + + * **Shape Clipping** – it is now possible to [clip a graphics context based on an arbitrary shape](https://www.codenameone.com/blog/shape-clipping-bubble-transition.html) + + * **ToastBar** – allows [posting “hints” visually](https://www.codenameone.com/blog/toastbar-gaussian-blur.html) to a hint area + + * **Toolbar** is [now the default](https://www.codenameone.com/blog/toolbar-default-millimeter-sizes-weekly-releases.html) & +has a refined implementation/usage + + * **SignatureComponent** – allows us to [accept user signatures](https://www.codenameone.com/blog/downloads-callbacks-signature-more.html) + + * **Gaussian Blur** – supported on [images and dialogs](https://www.codenameone.com/blog/downloads-callbacks-signature-more.html) + + * **ParparVM** – now has [better performance in micro-benchmarks](https://www.codenameone.com/blog/seo-gallery-performance-javascript-gradle.html) + +You can see the full list of changes to Codename One in [the github repository](https://github.com/codenameone/CodenameOne/commits/master). + +### Lowlights + +The following are things we are still working on or failed to bring to the front for this release. We are aware of +them and are working on improving them: + + * Demos – We were supposed to modernize our demos. Almost all of them still use Java 5 and old themes. None +use the new material design icon fonts. This makes them feel antiquated, we hope to fix this early in the 3.5 cycle + + * Windows port – We actually [made great progress on this](https://www.codenameone.com/blog/new-windows-port.html) & +also [posted the full source code](https://www.codenameone.com/blog/windows-idea-enum-values-contactsmanager-refresh.html). +Just yesterday we posted [additional good news on the subject](/blog/windows-phone-8-1-uwp-support.html)! +However, it’s still incomplete for release and needs quite a bit of work as it is a **huge** task. We are making a lot +of progress though and we are optimistic that 3.5 could have UWP support. + + * GUI Builder – This is the biggest failure of this release. One of our core goals was to get the GUI builder +to production grade in 3.5 and we failed with that. It’s much stabler but we can’t call it 1.0 at this time…​ +This is our highest priority right now. We will try to get the GUI builder to 1.0 well before 3.5 is ready and will +hopefully release/announce it separately. + +### Onwards to 3.5 + +Besides the lowlights above which must be addressed, there are several other things we are looking at for 3.5: + + * Java 8 all the way – we will make Java 8 into the default build mode. Once that is in order we will experiment +with “only” Java 8 mode for newer builds. +Assuming this will work we will switch to Java 8 thru our entire stack and Codename One builtin code will be able +to use Java 8 language features. + + * Videos & Even Better Docs – We will increase our video output now that our documentation has improved. We +are still working on even better documentation than what we have right now. We’re not ready for announcements +yet but we have some interesting ideas + + * We will continue the trend of using Codename One to build everything. This trend started with the +certificate wizard which is one of our most popular features. It continued with the new GUI builder and preferences +dialog for our [IntelliJ IDEA support](/blog/a-new-idea.html). + +#### Schedule + +Codename One 3.5 is scheduled for Tuesday August 2nd 2016. Version 3.6 is currently scheduled for December of +2016. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Kyri Ioulianou** — May 3, 2016 at 8:33 am ([permalink](https://www.codenameone.com/blog/codename-one-3-4-now-live.html#comment-22858)) + +> Kyri Ioulianou says: +> +> When I check for updates in Netbeans it says the latest version available is only 3.3.4 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-4-now-live.html) + + +### **Shai Almog** — May 3, 2016 at 10:57 am ([permalink](https://www.codenameone.com/blog/codename-one-3-4-now-live.html#comment-22461)) + +> Shai Almog says: +> +> We released the update last week so libraries should be up to date. The Eclipse and IDEA plugins should be at the right version, however since NetBeans goes thru manual verification by the NetBeans team it sometimes take a while for the update (which we submitted almost a week ago) to go thru that process. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-4-now-live.html) + + +### **Geertjan** — May 3, 2016 at 11:08 am ([permalink](https://www.codenameone.com/blog/codename-one-3-4-now-live.html#comment-22449)) + +> Geertjan says: +> +> I just had a look in the Plugin Manager in NetBeans IDE 8.1. The latest version of Codename One available is 3.4.0. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-4-now-live.html) + + +### **Gareth Murfin** — May 3, 2016 at 11:24 am ([permalink](https://www.codenameone.com/blog/codename-one-3-4-now-live.html#comment-22493)) + +> Gareth Murfin says: +> +> Great news!!! What an update, shame about the GUI builder, Im looking forward to that. I may even swap to IntelliJ plugin see what its like! Also when will cocoa pods be fully supported on iOS side ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-4-now-live.html) + + +### **Shai Almog** — May 3, 2016 at 11:25 am ([permalink](https://www.codenameone.com/blog/codename-one-3-4-now-live.html#comment-22567)) + +> Shai Almog says: +> +> Notice Geertjans comment that 3.4 is already up on NetBeans. We have a cocoa pods announcement coming soon… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-4-now-live.html) + + +### **Chen Fishbein** — May 3, 2016 at 12:36 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-4-now-live.html#comment-22622)) + +> Chen Fishbein says: +> +> Hi Geertjan, +> I think I see an issue with the plugin center. is it possible that the plugin center won’t return the most latest plugin version if a user haven’t updated for a while? for example if a User was on version 3.3.3 and he haven’t updated the plugin for a while and in the meantime we uploaded 3.4.0 version. when he search for updates the plugin center will updated him to 3.3.4 instead of skipping that version and offering 3.4.0. is this a known issue? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-4-now-live.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-3-5-now-live.md b/docs/website/content/blog/codename-one-3-5-now-live.md new file mode 100644 index 0000000000..e4f83fb409 --- /dev/null +++ b/docs/website/content/blog/codename-one-3-5-now-live.md @@ -0,0 +1,110 @@ +--- +title: Codename One 3.5 Now Live +slug: codename-one-3-5-now-live +url: /blog/codename-one-3-5-now-live/ +original_url: https://www.codenameone.com/blog/codename-one-3-5-now-live.html +aliases: +- /blog/codename-one-3-5-now-live.html +date: '2016-08-01' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-3-5-now-live/codenameone35.jpg) + +We are thrilled to announce the immediate availability of Codename One 3.5! + +Version 3.5 is a **huge** release that includes the long awaited Windows Universal Platform (UWP) support and brings the new GUI builder out of beta. + +### Highlights of this Release + + * **Beta version of the UWP (Universal Windows Platform) Port** – Codename One [supports native Windows 10 universal apps](https://www.codenameone.com/manual/appendix-uwp.html) that you can sell thru the Windows Store + + * **New GUI Builder Release** – We released the [new GUI builder](https://www.codenameone.com/blog/using-the-new-gui-builder.html). It still has rough edges but is improving at a rapid pace + + * **New Settings UI featuring the Extensions Library** – This is a complete [redesign of the core settings/preferences](http://www.codenameone.com/blog/new-preferences-command-state-localization-locking.html) within Codename One. It started as the settings UI for IntelliJ/IDEA and we liked it so much we decided to make it the default for all IDE’s. This tool makes the process of [installing/discovering cn1libs (libraries/extensions/plugins)](http://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html) trivial! + + * **Experimental New Peer Component Mode** – We now allow [more elaborate lightweight heavyweight mixing mode](http://www.codenameone.com/blog/new-android-peer-mode.html) on the Android port and soon on other ports + + * **Seamless support for Android Marshmallow permissions** – This requires [no code changes](https://www.codenameone.com/blog/switching-on-android-marshmallow-permission-prompts.html) for most applications. We also support this in the [simulator & native code](https://www.codenameone.com/blog/marshmallow-permissions-in-the-simulator-and-native-code.html). + + * **Removed Skins from Simulator** – We [moved skins to the more menu](https://www.codenameone.com/blog/unskin-proxy-support.html) where you can be download them dynamically. We also added new skins and a [skin designer tool](https://www.codenameone.com/blog/skin-designer.html)…​ +This reduced the size of our distribution by almost 30MB! + + * **Added Background Fetch Support** – This allows [downloading in the background in iOS/Android](http://www.codenameone.com/blog/background-fetch.html) + + * **New Accordion Component** – Allows [folding/expanding UI elements](https://www.codenameone.com/blog/accordion-component.html) + + * **New ComponentAnimation methods for Compound Animations** – allow more [elaborate animation effects](https://www.codenameone.com/blog/composite-animations.html) + + * **Material Icons Enhancements** – [used thru the code](https://www.codenameone.com/blog/toolbar-back-easier-material-icons.html) and map to [different component selection states](http://www.codenameone.com/blog/pressed-selected-icon-font-utf-8.html) seamlessly + + * **Search Command in the Toolbar** – It’s now trivial to [add search](https://www.codenameone.com/blog/toolbar-search-mode.html) into the title area + + * **Proxy Support** – [for simulator & build process](https://www.codenameone.com/blog/unskin-proxy-support.html) + + * **Demos Rewritten** – we rewrote/revisited the following demos: [Property Cross](https://www.codenameone.com/blog/property-cross-revisited.html), [Charts](https://www.codenameone.com/blog/charts-demo-revisited.html), [Social Boo](https://www.codenameone.com/blog/social-boo-revisited.html), [Dr. Sbaitso](http://www.codenameone.com/blog/dr-sbaitso-revisited.html), [Chrome](https://www.codenameone.com/blog/chrome-demo.html), +[Clock](https://www.codenameone.com/blog/clock-demo.html) & [Camera](https://www.codenameone.com/blog/camera-demo.html). They are now all Java 8 based, they use the newer API’s such Toolbar and proper fonts. + + * **Simplified ToastBar** – Added [simple error message handling](https://www.codenameone.com/blog/zip-and-toast.html), regular [messages](https://www.codenameone.com/blog/toastbar-messages.html) and [download progress indication](https://www.codenameone.com/blog/toast-downloads.html) + + * **Finished migration to the new push servers** – the last few users are leaving and [soon the old servers will be retired](https://www.codenameone.com/blog/migration-to-the-new-push-servers-completed.html) + +### Lowlights + + * Xcode 7 migration – this is something we tried to do and had to walk back. It’s more challenging to get this right but we hope to do this in the 3.6 cycle. + + * Demos – we didn’t finish all the demos and didn’t finish the most important one (Kitchen Sink). There isn’t much left there though…​ + + * Peer Component Support – we didn’t switch this on by default. We weren’t able to do this for other OS’s either in time for the release. + + * While we produced videos we didn’t produce more of them. The production of higher quality videos is more intense and hard to fit into our schedules + +### Onwards to 3.6 + +With 3.6 we are aiming to introduce an offline build option for enterprise developers. We also have some other plans but they might stretch to 3.7. + +The lowlight issues above are important to us for the 3.6 release and we’d like to improve on them. + +#### Schedule + +Version 3.6 is scheduled for December of 2016. 3.7 is scheduled for April 4th 2017. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Nigel Chomba** — August 5, 2016 at 3:04 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-5-now-live.html#comment-22547)) + +> Nigel Chomba says: +> +> how can i get access to the updated kitchenSink Demo?.Cheers +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-5-now-live.html) + + +### **Shai Almog** — August 6, 2016 at 4:54 am ([permalink](https://www.codenameone.com/blog/codename-one-3-5-now-live.html#comment-22364)) + +> Shai Almog says: +> +> We’d like to publish it in the next couple of weeks. It’s not ready yet… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-5-now-live.html) + + +### **Hristo Vrigazov** — August 13, 2016 at 4:58 am ([permalink](https://www.codenameone.com/blog/codename-one-3-5-now-live.html#comment-21452)) + +> Hristo Vrigazov says: +> +> Pure awesomeness! Way to go guys! Thanks for the amazing product! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-5-now-live.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-3-6-now-live-special-sale.md b/docs/website/content/blog/codename-one-3-6-now-live-special-sale.md new file mode 100644 index 0000000000..cf4ea1e0e7 --- /dev/null +++ b/docs/website/content/blog/codename-one-3-6-now-live-special-sale.md @@ -0,0 +1,215 @@ +--- +title: Codename One 3.6 Now Live & Special Sale +slug: codename-one-3-6-now-live-special-sale +url: /blog/codename-one-3-6-now-live-special-sale/ +original_url: https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html +aliases: +- /blog/codename-one-3-6-now-live-special-sale.html +date: '2017-01-15' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-3-6-now-live-special-sale/codenameone-3-6.jpg) + +[Codename One](/), the “industry defining” **Write Once Run Anywhere native mobile app platform for Java developers** has just published version 3.6. +We’re thrilled with this release whose key features are offline build support and official support for UWP (Universal Windows Platform). Starting with this release we are changing the scope for Codename One: Instead of trying to be “as good as native” we’d like to aim to be “better than native”. + +We already offer many advantages over native platform development: + + * Faster builds and build cycles + + * Portability + + * Easier customization of the UI with ability to control every pixel + +With 3.6 we hammered down all of these to a fine tuned machine and moving forward we’d like to build the Codename One that is better than native. + +You can check out our press release [here](http://news.cision.com/dakota-digitalltd/r/one-of-a-kind-java-development-tool-expands-features-giving-developers-further-innovative-capabiliti,c2167285). + +### Special Sale + +To celebrate this release we are offering the first year of the annual enterprise subscription at half of the standard monthly price which totals at 199 USD per month (2,388 USD for the year). You can take advantage of this offer by logging in and clicking the button below. This will allow you to take advantage of all the enterprise features including offline builds and enhanced support…​ + +This special offer expires on Friday! + +Last year we had a [special promotion for JavaScript builds](/blog/a-thank-you-an-important-update-on-android-builds.html). A lot of you got to experiment with the JavaScript port thanks to that and it will be ending very soon! +So if you found that valuable this is probably the best price you will get on an enterprise subscription. + +__ | The special deal has elapsed, thanks for all of you who signed up! +---|--- + +### Highlights of this Release + + * **Offline Build Support** – Building thru the cloud is one of the “defining features” of Codename One, but some government level customers need the [ability to build offline](https://www.codenameone.com/blog/offline-build.html) due to regulatory concerns + + * **Production grade UWP (Universal Windows Platform) Port** – [UWP](https://www.codenameone.com/manual/appendix-uwp.html) allows seamless native support for Windows 10 on Intel/ARM devices & PC’s such as the very popular Surface line + + * **New GUI Builder Release** – We released the [new GUI builder](https://www.codenameone.com/blog/using-the-new-gui-builder.html). It still has rough edges but is improving at a rapid pace + + * **Round Borders** – [Round style borders](https://www.codenameone.com/blog/round-border-in-the-designer.html) are available now both in the designer and code + + * **Floating Action Button** – New [FloatingActionButton](https://www.codenameone.com/blog/floating-button.html) component that allows [badging](https://www.codenameone.com/blog/badging-arbitrary-components.html) as well + + * **In App Purchase Subscriptions & Receipts** – We completely rewrote the IAP documentation and added support for [subscriptions](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html) + + * **Security Enhancements** – We introduced [seamless storage encryption](https://www.codenameone.com/blog/seamless-storage-encryption.html) & [certificate pinning (SSL Pinning)](https://www.codenameone.com/blog/certificate-verification-avoid-pinning-vulnerability.html) + + * **New & Remastered Demos** – [Demos](https://www.codenameone.com/demos.html) were overhauled and new demos were added based on PSD design showing the level of creativity that you can integrate into your applications + + * **URL & File API’s** – Easier porting for existing Java code thru [File & URL](https://www.codenameone.com/blog/file-url-java-mobile-compatibility.html) API’s + + * **Properties** – [Properties](https://www.codenameone.com/blog/properties.html) allow us to build terse/type safe efficient mapping to storage/database/XML/JSON etc. + + * **Newer Defaults** – [Java 8 & Android API 23](https://www.codenameone.com/blog/java-8-api-23-defaults.html) are now on by default as well as [xcode 7.3](https://www.codenameone.com/blog/xcode-migration-revisited-again.html) with xcode 8 coming soon. Android’s [peer component](https://www.codenameone.com/blog/new-peers-on-by-default-on-android.html) is also on by default + + * **Easy Caching** – [Caching HTTP](https://www.codenameone.com/blog/automatic-caching.html) has never been easier…​ + +### Lowlights + +Overall we are very happy with this release we think we dotted the i’s and crossed the t’s. This is to a large part due to the delay of the release from December. We still had to push back some issues to 3.7 but that’s always unavoidable. + +The one thing we really didn’t get out in this release is a new Codename One course which we’ve been working on for a while. We hope we’ll get it done during the 3.7 era but video production is always a big effort and we just don’t have enough hours in the day…​ + +### Onwards to 3.7 + +Version 3.7 work is already underway. We hope to get the z-ordering in native peers to work on all major platforms in this version. We think it will open up Codename One to a whole new type of application (e.g. Augmented Reality). + +Our biggest wish for 3.7 is on-device-debugging but it’s a big feature so it’s unclear if it’s something that we’ll be able to deliver soon. + +### We Need your Help + +[Spread the word](http://www.codenameone.com/blog/how-you-can-help-spread-codenameone.html), please let people know about us. + +Sign up for enterprise accounts, besides the huge benefits of an enterprise account these are the guys that keep the lights on here and allow us to build Codename One. If your company can afford it please take the time and upgrade to enterprise, this will allow us to work on the things that are important for your company! + +Thanks for reading this far and if you have any thoughts/suggestions of any kind please feel free to post below! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Boniface N. Githinji** — January 16, 2017 at 5:34 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-23308)) + +> Boniface N. Githinji says: +> +> These are great advancements. Kudos team CodenameOne. +> +> I can attest to just how great this platform is, just finished working on a new app and it’s incredibly gorgeous and goes a long way to show just what is possible with this platform. [https://play.google.com/sto…]() +> +> [https://uploads.disquscdn.c…]() [https://uploads.disquscdn.c…]() [https://uploads.disquscdn.c…]() [https://uploads.disquscdn.c…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + + +### **bryan** — January 16, 2017 at 7:44 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-23188)) + +> bryan says: +> +> Screenshots on the app store look quite impressive. Well done ! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + + +### **Shai Almog** — January 17, 2017 at 6:47 am ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-23234)) + +> Shai Almog says: +> +> You guys made a lot of progress since the screenshots were added here: [https://www.codenameone.com…]() +> We’ll try to update to the latest screenshots! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + + +### **Chidiebere Okwudire** — January 17, 2017 at 6:58 am ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-24119)) + +> Chidiebere Okwudire says: +> +> Great job guys! I’ve been out of touch lately due to other commitments but I follow the updates and look forward to when I can get busy with CodenameOne again. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + + +### **Lukman Javalove Idealist Jaji** — January 17, 2017 at 2:42 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-23087)) + +> Lukman Javalove Idealist Jaji says: +> +> Sasa boniface… +> +> did you generate your UI from a PSD? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + + +### **Boniface N. Githinji** — January 17, 2017 at 3:16 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-23242)) + +> Boniface N. Githinji says: +> +> Thanks bryan. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + + +### **Boniface N. Githinji** — January 17, 2017 at 3:16 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-23163)) + +> Boniface N. Githinji says: +> +> Hi Lukman, no; did it all in Java from scratch. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + + +### **Boniface N. Githinji** — January 17, 2017 at 3:20 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-22918)) + +> Boniface N. Githinji says: +> +> Thanks Shai. Yes indeed. This is a great platform, we are big believers in WORA and will keep shipping all our mobile apps via CodenameOne. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + + +### **Lukman Javalove Idealist Jaji** — January 17, 2017 at 5:39 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-23267)) + +> Lukman Javalove Idealist Jaji says: +> +> Fantastic…….good job man….really good job +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + + +### **Lukman Javalove Idealist Jaji** — January 17, 2017 at 6:06 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-23309)) + +> Lukman Javalove Idealist Jaji says: +> +> pleae give me your email boniface….. thank you +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + + +### **Chen Fishbein** — January 18, 2017 at 11:48 am ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-23287)) + +> Chen Fishbein says: +> +> Nice one! well done! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + + +### **Boniface N. Githinji** — February 16, 2017 at 1:28 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-6-now-live-special-sale.html#comment-23045)) + +> Boniface N. Githinji says: +> +> Find our review of the Codename One platform here – [http://sematime.com/product…]() +> +> Keep doing the good work we’ll keep evangelizing this framework here in Africa. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-6-now-live-special-sale.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-3-6-release-plan.md b/docs/website/content/blog/codename-one-3-6-release-plan.md new file mode 100644 index 0000000000..6894309f11 --- /dev/null +++ b/docs/website/content/blog/codename-one-3-6-release-plan.md @@ -0,0 +1,26 @@ +--- +title: Codename One 3.6 Release Plan +slug: codename-one-3-6-release-plan +url: /blog/codename-one-3-6-release-plan/ +original_url: https://www.codenameone.com/blog/codename-one-3-6-release-plan.html +aliases: +- /blog/codename-one-3-6-release-plan.html +date: '2017-01-03' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-3-6-release-plan/codenameone-3-6.jpg) + +We will release Codename One 3.6 on the 16th of January, this means we will enter code freeze on the 9th during which only critical bugs will be fixed with peer review. Since Codename One is a SaaS product release cycles aren’t as crucial for most of us but they provide a framework both for versioned builds and for us to focus on the more mundane aspects of product maintenence. + +With 3.6 we are fine tuning the 4 releases per year approach we took in the past to a more convenient 3 – release per year cycle. This will allow us to deliver more refined releases while still **delivering them** which is harder to do without a fixed roadmap. + +Over the past few weeks we had to postpone many issues that we wanted to have in 3.6 due to the pressures of the looming release. We hope to address these issues early in the 3.7 release cycle. One such pain point is the support for z-ordering in peer components on iOS and other platforms (besides Android). This is a challenging feature and we just couldn’t justify something “half baked” so close to a stable release. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-3-7-live.md b/docs/website/content/blog/codename-one-3-7-live.md new file mode 100644 index 0000000000..3a67bc6574 --- /dev/null +++ b/docs/website/content/blog/codename-one-3-7-live.md @@ -0,0 +1,283 @@ +--- +title: Codename One 3.7 is Live +slug: codename-one-3-7-live +url: /blog/codename-one-3-7-live/ +original_url: https://www.codenameone.com/blog/codename-one-3-7-live.html +aliases: +- /blog/codename-one-3-7-live.html +date: '2017-06-26' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-3-7-live/codenameone-3-7.jpg) + +[Codename One](/) 3.7, the “Write Once Run Anywhere” mobile solution for Java developers is now live! +This exciting new release brings with it a surprising new overhaul of the Codename One GUI builder which now includes support to “auto-layout” allowing developers to place components with the ease/power of Photoshop or Illustrator.. + +Codename One is the only platform that…​ + + * Has Write Once Run Anywhere with no special hardware requirements and 100% code reuse + + * Compiles Java into native code for iOS, UWP (Universal Windows Platform), Android & even JavaScript + + * Is Open Source & Free with an enterprise grade commercial offering + + * Is Easy to use with 100% portable Drag & Drop GUI builder + + * Has Full access to underlying native OS capabilities using the native OS programming language (e.g. Objective-C) without compromising portability + + * Lets you use native widgets (views) and mix them with Codename One components within the same hierarchy (heavyweight/lightweight mixing) + +To learn more about Codename One check out the [about page](/about.html) you can [download it for free right now](/download.html). + +### From Lowlight to Feature + +When we released Codename One 3.6 we had this to say: + +> The one thing we really didn’t get out in this release is a new Codename One course which we’ve been working on for a while. We hope we’ll get it done during the 3.7 era but video production is always a big effort and we just don’t have enough hours in the day…​ + +— Codename One 3.6 release announcement + +Yesterday we [announced the new Codename One Academy](/blog/launching-codename-one-academy.html) which includes 3 new media rich courses that will cover everything needed to build gorgeous real world apps. This is new original materials with a 2 year monthly update commitment roadmap! + +As is our custom with some releases we are also running a promotion on these courses and our [special offer expires on July 3rd](/blog/launching-codename-one-academy.html) so hurry up! + +### Highlights of this Release + +Here are the top 5 features of this release illustrated in this short video, check out further details below. + + * **GUI Builder Auto Layout** – We now support an inset based GUI builder mode that allows positioning components in a far more fluid way. We are still working on tutorials for this new mode and it’s highly experimental but you can start using it right now! +In addition to that we made numerous enhancements to the UX of the GUI builder further refining it + + * **Live Style Customization** – The UI design of the application can be [customized directly from the simulator](/blog/edit-styles-simulator.html) + + * **Z-Ordering on All OS’s** – You can mix native components e.g. maps, video. With Codename One components and draw on top of them + + * **Properties SQL & UI Binding** – Support for database mapping (ORM), parsing & UI binding/generation seamlessly using the properties API + + * **Rest API for Terse Networking** – New builder style REST API that abstracts some of the verbosity of `ConnectionRequest` + + * **VM API Enhancements** – Added some core VM classes and API’s such as [java.lang.Number](https://github.com/codenameone/CodenameOne/issues/1783), `CharSequence`, [exception chaining](https://github.com/codenameone/CodenameOne/issues/1991) etc. + + * **Terse Syntax** – New [CN API](/blog/static-global-context.html) allows developers to write more concise code, new helper API’s such as `addAll` & a jquery style [component selector](/blog/jquery-css-style-selectors-for-cn1.html) + + * **Security Oriented API’s** – New API’s for detecting certificates on https servers as well as API’s for touch ID, jailbreak detection and [more](/manual/security.html) + + * **Thread Helper & Threadsafe SQLite API’s** – A new API for communicating with threads & a new [threadsafe wrapper for sqlite](/blog/threadsafe-sqlite.html) + + * **Better Desktop/Web API’s** – We now support API’s such as mouse cursor customization, split pane, mouse hover events etc. which allow more elaborate desktop apps. We also include an experimental new “desktop skin” to debug desktop apps + + * **Experimental “On Top” Sidemenu & Form Layered Pane** – Side menu can now be [on top](/blog/sidemenu-on-top.html) of the UI and potentially on top of the entire form with a new layered pane mode + + * **ParparVM Performance Improvements** – Some of the code such as method invocations will now compile to the C equivalent of that code in terms of performance, many basic numeric operations are much faster thanks to VM optimizations and code is up to 40% smaller over 3.6 + + * **Two Factor Authentication in Certificate Wizard** – The certificate wizard now supports 2 factor authentication in your apple account + + * **Faster iOS Builds** – Build times in the Apple servers are up to x3 faster for some users with exceptionally long build times. + + * **Test Recorder & Toolbar** – The test recorder now [works correctly with the toolbar](/blog/test-recorder-toolbar.html) + +### Lowlights + +As we always do with a release we’d like to shine a spotlight on the things 3.7 can do better and the things 3.8 can improve on. Overall we are thrilled with this release but here are a few things we can do better: + + * On device debugging – this was planned for 3.7 but didn’t make it. We have a running proof of concept but that also highlights the amount of work needed to bring this to production grade. Since 3.8 is relatively close by it’s hard for us to say if it will be a feature of 3.8. + + * Improved default themes & material design – this is an area we need to spend more time on. We are attacking it one component at a time but that is often challenging. We can use your help in filing issues and pull requests to improve the situation. If you see something that doesn’t look good or doesn’t look native [go to the issue tracker & create a new issue](http://github.com/codenameone/CodenameOne/issues/new) in it include a screenshot of how it looks now and a screenshot of how it should look. This helps us focus on the things that are important to our users. Even if we know about the problem an issue helps us focus! + + * Theme & Localization – The new GUI builder is starting to take shape and it’s time to turn our attention to the other rolls that the old designer tool handles. We already made some improvements to styling but we can go further. + +### Onwards to 3.8 + +We completed almost everything we wanted to do for 3.7, to be fair that’s not to hard as we delayed the release due to the bootcamp and that gave us extra time. + +The next version will be out in mid November which already feels damn close by now so I’m not sure which ones of the lowlights above we’ll be able to address by then but those are our biggest priorities not necessarily in that order. + +The one feature that we did announce for 3.8 is [Kotlin support](/blog/kotlin-wora-ios-iphone-windows-android.html). We ran a survey whose results included a bit of a surprise to us, it’s something I’ll discuss in an upcoming post. + +### We Need your Help + +[Spread the word](http://www.codenameone.com/blog/how-you-can-help-spread-codenameone.html), please let people know about us. + +Sign up for enterprise accounts, besides the huge benefits of an enterprise account these are the guys that keep the lights on here and allow us to build Codename One. If your company can afford it please take the time and upgrade to enterprise, this will allow us to work on the things that are important for your company! + +Thanks for reading this far and if you have any thoughts/suggestions of any kind please feel free to post below! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Dalvik** — June 27, 2017 at 1:11 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-23423)) + +> Dalvik says: +> +> I’ve just tried the new GUI builder, at first it was a bit confusing as it felt a bit like I can put a component anywhere but then I watched the video and it “clicked”. +> I really like the drag and drop UI of the GUI builder, it’s pretty smooth… Was it built with JavaFX? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Shai Almog** — June 27, 2017 at 1:16 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-24208)) + +> Shai Almog says: +> +> Thanks. +> No, it’s actually written in Codename One… Just like the Codename One Settings. Just goes to show you what you can do with some attention to detail. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Mac Flanegan** — June 27, 2017 at 1:30 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-23525)) + +> Mac Flanegan says: +> +> Congratulations on the updates of this new version! +> +> PS: In Delphi this feature is called “Anchors” what I think would be a more appropriate name. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Shai Almog** — June 27, 2017 at 1:37 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-24149)) + +> Shai Almog says: +> +> Thanks! +> Were anchors automatically placed and bound with percentage or millimeter units to other components? +> I haven’t used it in years so I don’t recall… +> +> I was for constraints and in Java there is a Spring layout (which I glad he didn’t pick as Spring is already deeply used in Java). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Pugazhendi E** — June 27, 2017 at 1:46 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-23217)) + +> Pugazhendi E says: +> +> Congrats 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Mac Flanegan** — June 28, 2017 at 5:08 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-23572)) + +> Mac Flanegan says: +> +> In Delphi this a more simple feature. The reference is “always” the parent component. But the idea is the same. Delphi has constraints too. +> +> AutoLayout reminds me the automatic arrangement of components, as it already exists in codename. So the suggestion to use Anchors. In my opinion Anchors says more about what this feature does. +> +> Before I see it working, I even thought: – but the codenameonde already does autolayout … +> +> But again, congratulations to the new features … +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Shai Almog** — June 29, 2017 at 3:54 am ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-23580)) + +> Shai Almog says: +> +> Autolayout is a term used in iOS so we chose it to keep it familiar. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Francesco Leoni** — June 29, 2017 at 6:35 am ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-23589)) + +> Francesco Leoni says: +> +> Hi Shai, congratulations on the new release! +> +> Is it possible to open an old Form (created using the previous GUuiBuilder) with the new GuiBuilder, or to convert an old Form to the new format? +> At present I can use the new GB interface only wher I create a brand new Form. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Shai Almog** — June 29, 2017 at 8:56 am ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-23459)) + +> Shai Almog says: +> +> Thanks! +> +> Right now there are 3 modes: +> – Old GUI builder – that’s the old designer tool where we still have theming. That’s a completely separate tool with the state machine etc. +> You can use the conversion tool command line as explained here: [https://www.codenameone.com…]() to convert that old GUI to the new GUI builder. Notice that it will not take advantage of the new auto-layout… +> +> – New GUI builder code created pre-3.7. These forms have auto-layout off by default for maximum compatibility as this might break some existing logic. +> +> – New GUI builder forms created with autolayout +> +> If you are referring to converting the GUI builder code pre-3.7 to post 3.7 you can easily do that but it will require a bit of hacking. Just open the .gui XML file and set the layout of the form to be layered layout. Then set autoLayout=”true” in the top level component tag. This will enable the new layout mode on an older form. Everything might be “messed up” after you do that which might require some work of fixing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Francesco Leoni** — June 29, 2017 at 7:55 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-23636)) + +> Francesco Leoni says: +> +> Thankyou so much for your reply. Unfortunately that didn’t do the trick: after modifying the top level component like this (see below), the GUI builder is not starting at all. +> +> component type=”Form” layout=”LayeredLayout” title=”MyApp” name=”GuiComponent” autoLayout=”true”> +> +> Lauching Gui builder from commandline I can see some null pointer exceptions like the one below: +> +> [EDT] 0:0:0,316 – Exception: java.lang.NullPointerException – null +> java.lang.NullPointerException +> at com.codename1.ui.layouts.LayeredLayout$LayeredLayoutConstraint.setInsets([LayeredLayout.java]():1871) +> at com.codename1.apps.guibuilder.GuiPersister.createComponent([GuiPersister.java]():282) +> at com.codename1.apps.guibuilder.GuiPersister.load([GuiPersister.java]():99) +> at com.codename1.apps.guibuilder.GUIBuilder.connected([GUIBuilder.java]():76) +> at com.codename1.apps.guibuilder.GUIBuilder.start([GUIBuilder.java]():107) +> at com.codename1.apps.guibuilder.desktop.GUIBuilderMain$[11.run](:427) +> at com.codename1.ui.Display.processSerialCalls([Display.java]():1056) +> at com.codename1.ui.Display.mainEDTLoop([Display.java]():873) +> at [com.codename1.ui.RunnableWr…](:120) +> at [com.codename1.impl.Codename…](:176) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Shai Almog** — June 30, 2017 at 3:59 am ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-23349)) + +> Shai Almog says: +> +> Sorry, it seems I remembered this incorrectly and the attribute should be autolayout lower case not camel case. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Francesco Galgani** — June 30, 2017 at 11:27 am ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-23376)) + +> Francesco Galgani says: +> +> Are these new features (in particular the new Gui Builder) covered in the three courses of the Codename One Academy? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + + +### **Shai Almog** — June 30, 2017 at 12:46 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-7-live.html#comment-23518)) + +> Shai Almog says: +> +> Some of them are, some are coming soon and some are not. +> In particular the GUI builder should be coming soon. +> +> I started working on a module but it ended up being too problematic to document a tool that’s changing so quickly (case in point here). Hopefully this marks a stable point where I can start working on a GUI builder module which will hopefully be the first module I add after finishing this work. +> +> I’m considering building parts of the Uber app using the GUI builder but I’m not sure if it will work well with that use case. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-7-live.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-3-8-live.md b/docs/website/content/blog/codename-one-3-8-live.md new file mode 100644 index 0000000000..7d3506a77b --- /dev/null +++ b/docs/website/content/blog/codename-one-3-8-live.md @@ -0,0 +1,194 @@ +--- +title: Codename One 3.8 is Live +slug: codename-one-3-8-live +url: /blog/codename-one-3-8-live/ +original_url: https://www.codenameone.com/blog/codename-one-3-8-live.html +aliases: +- /blog/codename-one-3-8-live.html +date: '2017-11-13' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-3-8-live/codenameone-3-8.jpg) + +We are thrilled to announce the release of [Codename One](https://www.codenameone.com/) 3.8. Codename One is an open source “Write Once Run Anywhere” mobile solution for Java developers! +This new release significantly refines the native look and feel of Codename One, it brings the GUI builder to a new level with styling support. It finally adds Mac OS appstore distribution support which means all the major appstores are now supported targets for Codename One applications. + +Codename One is the only platform that…​ + + * Has **Write Once Run Anywhere** with no special hardware requirements and 100% code reuse + + * Compiles **Java** or **Kotlin** into native code for iOS, UWP (Universal Windows Platform), Android & even JavaScript + + * Is **Open Source & Free for commercial use** with an enterprise grade commercial support + + * Is Easy to use with **100% portable Drag & Drop GUI builder** + + * Has Full access to underlying native OS capabilities using the **native** OS programming language (e.g. Objective-C) without compromising portability + + * Has full **control over every pixel** on the screen! Just override paint and draw or use a glass pane to draw anywhere…​ + + * Lets you **use native widgets (views) and mix them with Codename One components** within the same hierarchy (heavyweight/lightweight mixing) + +To learn more about Codename One check out the [about page](https://www.codenameone.com/about.html) you can [download it for free right now](https://www.codenameone.com/download.html). + +As part of the release we significantly refined our developer guide which is now also available in [print form on Amazon](https://www.amazon.com/dp/1549910035). Notice that this guide is available for free [here](https://www.codenameone.com/manual/) & in [pdf format](https://www.codenameone.com/files/developer-guide.pdf). This developer guide is a community effort which you can contribute to as explained [here](https://www.codenameone.com/blog/tip-edit-docs-fun-profit.html). + +### Highlights of this Release + +The top 5 features of this release are covered in this short video, check out further details below…​ + + * **Improved Native Look & Feel** – We changed the core look of [buttons](https://www.codenameone.com/blog/pixel-perfect-material-buttons-part-2.html), [labels](https://www.codenameone.com/blog/pixel-perfect-material-buttons.html), [text components](https://www.codenameone.com/blog/pixel-perfect-text-input-part-2.html), [ripple effect](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html) and more. The goal is to make Codename One applications indistinguishable from native OS apps out of the box + +![Before: Codename One 3.7 text Input \(on Android\)](/blog/codename-one-3-8-live/pixel-perfect-text-field-android-codenameone-before.png) + +Figure 1. Before: Codename One 3.7 text Input (on Android) + +![After: Codename One 3.8 text Input \(on Android\)](/blog/codename-one-3-8-live/pixel-perfect-text-field-android-codenameone-font.png) + +Figure 2. After: Codename One 3.8 text Input (on Android) + + * **Kotlin Support** – [Kotlin](https://www.codenameone.com/blog/kotlin-support-public-beta.html) is now officially supported by Codename One and works out of the box + + * **On Top Side Menu** – The [on top side menu](https://www.codenameone.com/blog/pixel-perfect-on-top-menu.html) adapts the side menu UI to render on-top of the application instead of below but it’s really a complete rewrite of the old `SideMenuBar` which was implemented in a problematic way. The new on-top mode works better with native peers such as maps and can be extended more easily + + * **GUI Builder Styling Support** – There are a lot of enhancements and refinements in the new GUI builder one of the big ticket features is the new [style UI](https://www.codenameone.com/blog/always-on-top-style-parser.html) which allows you to style an element without leaving the GUI builder + + * **Mac OS Appstore Support** – We now support building [signed Mac OS apps](https://www.codenameone.com/blog/mac-appstore-builds-device-farms.html) which means we now support all the major vendor appstores. We already support iOS/Android stores and Windows/Microsoft’s store (via the UWP port). The Mac appstore was the last major vendor whose store we didn’t support out of the box + + * **Signal Handling & Fast UTF in ParparVM** – [ParparVM](https://github.com/codenameone/CodenameOne/tree/master/vm) is our open source iOS VM. It now [handles low level OS signals](https://www.codenameone.com/blog/vm-changes-updates.html) to catch illegal access and convert it to Java exceptions. This means performance is slightly better but more importantly: you can catch errors even when they originate from native code. We also made significant improvements to the UTF-8 decoding logic which should make apps that rely on localized data faster and more memory efficient + + * **Theme Enhancements** – We added many new capabilities into the Codename One themes specifically: [Fractional padding/margin](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html), [Rounded border](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html), [Underline borders](https://www.codenameone.com/blog/millimeter-underline.html) & more + + * **Table Sorting** – You can now [sort](https://www.codenameone.com/blog/sortable-table.html) a table by clicking on the column header + +There are many other features both big and small. Check out our [blog](https://www.codenameone.com/blog/) and the github [project history](https://github.com/codenameone/CodenameOne/commits/master). + +### Lowlights + +As we always do with a release we’d like to shine a spotlight on the things this version could do better and the things the next version can improve. Overall we are thrilled with this release but here are a few things we can do better: + + * On device debugging – this was planned before for 3.7 but didn’t make it. We have a running proof of concept but that also highlights the amount of work needed to bring this to production grade. We didn’t think it will make it for 3.8 and I’m not optimistic about 4.0 with our current workload. We think this will be a great enhancement but right now we think theming is more important + + * Improved default themes & material design – we made huge strides in this area but we are still way behind and our demos still don’t reflect the progress we made. Hopefully by the time 4.0 rolls around we’ll be in a different place entirely + + * Theme & Localization – Steve added some better theming to the new GUI builder. We think we can improve on this further and generally improve theming. Localization is something that regressed a bit from the old GUI builder which allowed for great automatic localization. We need something more “seamless” in this department + +### Onwards to 4.0 + +We have way more time for the 4.0 release so we can probably fit in more things than we did in 3.8. One of the difficulties in 3.8 is that a lot of the time between 3.7 and 3.8 was spent in summer months that are less productive. We fully expect 4.0 to be far richer in terms of features. + +By the time 4.0 rolls around we should have two new major demos/tutorials in the [Codename One Academy](https://codenameone.teachable.com/). + + * The Uber style application + + * A social network style application + +We’ve already laid some ground work for the Uber style app and we plan to push it out before the end of the year. This continues the 3 major trends we are trying to drive: + + * Better design + + * Better docs + + * More “ready made templates” + +Another big focus which we’ll see in 4.0 is quality and continuous integration. Our QA process is now open as part of our continuous integration support. We are now running automated tests of all our commits on device farms which should make future versions of Codename One far more stable. + +### We Need your Help + +We got a record number of community pull requests during the 3.8 timeline, that is fantastic! + +If you think we are doing a good job and appreciate our help please help us by: + + * [Spreading the word](https://www.codenameone.com/blog/how-you-can-help-spread-codenameone.html) + + * [Edit our docs](https://www.codenameone.com/blog/tip-edit-docs-fun-profit.html) + + * [Edit our sources and submit bug fixes](https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html) + + * Or just sign up for enterprise accounts which literally keep the lights on here…​ If your company can afford it please take the time and upgrade to enterprise, this will allow us to work on the things that are important for your company! + +Thanks for reading this far and if you have any thoughts/suggestions of any kind please let us know! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Dalvik** — November 14, 2017 at 2:33 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-8-live.html#comment-23539)) + +> Great video, loved the narration… +> +> I really liked the new look and feel changes at least based on the screenshots, I need to adapt some of my code/themes to use this. I’m personally pretty excited about a better TDD workflow. I found this a bit hard to do up to now. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-8-live.html) + + +### **Francesco Galgani** — November 15, 2017 at 1:58 pm ([permalink](https://www.codenameone.com/blog/codename-one-3-8-live.html#comment-23876)) + +> What’s code you used to generate the “Figure 2. After: Codename One 3.8 text Input (on Android)”? Is it an Instant UI generated using Properties? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-8-live.html) + + +### **James** — November 16, 2017 at 4:18 am ([permalink](https://www.codenameone.com/blog/codename-one-3-8-live.html#comment-23748)) + +> James says: +> +> Is there a plugin update for Eclipse? When I run Check For Updates, it lists a 3.8 update but then fails to install and says the repository can’t be found. If I look in Eclipse Marketplace, I see 3.7 as the latest version. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-8-live.html) + + +### **Shai Almog** — November 16, 2017 at 5:28 am ([permalink](https://www.codenameone.com/blog/codename-one-3-8-live.html#comment-23885)) + +> Shai Almog says: +> +> That code is discussed here: [https://www.codenameone.com…]() +> +> It’s also in the new developer guide update. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-8-live.html) + + +### **Shai Almog** — November 16, 2017 at 5:29 am ([permalink](https://www.codenameone.com/blog/codename-one-3-8-live.html#comment-23616)) + +> Shai Almog says: +> +> Thanks I do need to update the eclipse marketplace listing. It should work for the update. What’s your update URL? What’s the error? What’s your eclipse version? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-8-live.html) + + +### **James** — November 18, 2017 at 5:21 am ([permalink](https://www.codenameone.com/blog/codename-one-3-8-live.html#comment-23680)) + +> James says: +> +> I’m using Eclipse Version: Oxygen.1a (4.7.1a), Build id: M20171009-0410. The error I get is shown below. I went to the Marketplace and saw 3.8 listed and found a button there that said Update. I’m now updated to 3.8.0. +> +> An error occurred while collecting items to be installed +> session context was:(profile=SDKProfile, phase=org.eclipse.equinox.internal.p2.engine.phases.Collect, operand=, action=). +> No repository found containing: osgi.bundle,CodenameOnePlugin,3.8.0 +> No repository found containing: org.eclipse.update.feature,CodenameOneFeature,3.8.0 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-8-live.html) + + +### **Shai Almog** — November 18, 2017 at 5:34 am ([permalink](https://www.codenameone.com/blog/codename-one-3-8-live.html#comment-23567)) + +> Shai Almog says: +> +> Odd. I have Oxygen installed and I installed via the marketplace too. It worked as expected for me. Are you behind a proxy by any chance? +> If you try to install manually by using the update site: [https://www.codenameone.com…]() does it work? +> Do you maybe have an older Codename One update site imported from an older version of eclipse? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-3-8-live.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-4-0-taxi-live.md b/docs/website/content/blog/codename-one-4-0-taxi-live.md new file mode 100644 index 0000000000..33ae4eeab0 --- /dev/null +++ b/docs/website/content/blog/codename-one-4-0-taxi-live.md @@ -0,0 +1,168 @@ +--- +title: Codename One 4.0 "Taxi" is now Live +slug: codename-one-4-0-taxi-live +url: /blog/codename-one-4-0-taxi-live/ +original_url: https://www.codenameone.com/blog/codename-one-4-0-taxi-live.html +aliases: +- /blog/codename-one-4-0-taxi-live.html +date: '2018-03-19' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-4-0-taxi-live/codenameone-4-0-release-image-taxi.jpg) + +We are thrilled to announce the release of [Codename One](https://www.codenameone.com/) 4.0 – Taxi. Codename One is an open source “Write Once Run Anywhere” mobile solution for Java & Kotlin developers! +This new release overhauled the way Codename One is updated, added support for Progressive Web Apps (PWA’s), overhauled device skins & updated the backend iOS build tools. A major focus of this release is better support for peer (native) components, stability, unit testing and continuous integration. + +Codename One is the only platform that…​ + + * Has **Write Once Run Anywhere** with no special hardware requirements and 100% code reuse + + * Compiles **Java** or **Kotlin** into native code for iOS, UWP (Universal Windows Platform), Android & even JavaScript + + * Is **Open Source & Free for commercial use** with an enterprise grade commercial support + + * Is Easy to use with **100% portable Drag & Drop GUI builder** + + * Has Full access to underlying native OS capabilities using the **native** OS programming language (e.g. Objective-C) without compromising portability + + * Has full **control over every pixel** on the screen! Just override paint and draw or use a glass pane to draw anywhere…​ + + * Lets you **use native widgets (views) and mix them with Codename One components** within the same hierarchy (heavyweight/lightweight mixing) + + * Supports **seamless Continuous Integration** out of the box + +To learn more about Codename One check out the [about page](https://www.codenameone.com/about.html) you can [download it for free right now](https://www.codenameone.com/download.html). + +Version 4.0 is nicknamed Taxi because of the Uber Clone application that was developed with it for [the online course](https://codenameone.teachable.com/p/build-real-world-full-stack-mobile-apps-in-java) in the Codename One Academy. + +![Uber sidemenu next to the clone](/blog/codename-one-4-0-taxi-live/uber-app-side-menu-thumb.png) + +Figure 1. Uber sidemenu next to the clone + +![The Uber login form next to the clone](/blog/codename-one-4-0-taxi-live/side-by-side-thumb.png) + +Figure 2. The Uber login form next to the clone + +### Highlights of this Release + +The top 5 features of this release are covered in this short video, check out further details below…​ + + * **Progressive Web App Support (PWA)** – Progressive Web Apps allow us to try an application on the web and seamlessly transition to a native app. This makes user acquisition easier and installation frictionless. Codename One is the only tool in the world that [supports PWA’s seamlessly](https://www.codenameone.com/blog/progressive-web-apps.html) + + * **New Device Skins** – We updated the look of Codename One by releasing [33 new device skins](https://www.codenameone.com/blog/new-skins-san-francisco-font.html) including iPhone X & Pixel 2 XL. We included support for non-rectangular device skins and better device fidelity. We also added the ability to grab a screenshot that includes the skin frame around it + + * **Xcode 9.2** – Codename One apps are built using xcode 9.2. This [change is seamless](https://www.codenameone.com/blog/xcode-9-on-by-default.html) for most developers as the update happened on the build servers. Xcode 9.2 requires additional permission messages which are [added automatically by the simulator](https://www.codenameone.com/blog/xcode-9-mode.html) + + * **Update Framework** – Updates to Codename One libraries are now delivered using a [unified framework](https://www.codenameone.com/blog/new-update-framework.html) instead of separate adhoc tools + + * **Continuous Integration Support** – We now support [Travis CI](https://www.codenameone.com/blog/travis-ci-integration.html) out of the box seamlessly. Adding support for additional CI tools should be just as easy + + * **New Async JavaScript Interop API** – The Java → JavaScript bridge with the embeddable browser component was completely replaced. The [new implementation](https://www.codenameone.com/blog/new-async-java-javascript-interop-api.html) should be faster than the old system + + * **Builtin Unit Tests** – Unit tests to Codename One are [integrated into the core repository](https://www.codenameone.com/blog/updates-holidays.html) and are executed with every commit + + * **Improved Peer Components** – Multiple bugs and minor issues were fixed in the peer component layer this effectively enabled the Uber clone to [work properly with the native map](https://www.codenameone.com/blog/map-layout-update.html) + + * **Better Hello World** – The new Codename One projects [generate better code](https://www.codenameone.com/blog/new-default-code.html) that handles things such as network errors more effectively + + * **GUI Builder Refinements** – There were many refinements to the new GUI builder most notably: + + * Improved support for layout nesting in auto-layout mode – you can use all the existing layout managers within an autolayout parent + + * New Window Manager allows you to customize the positioning of the windows & palettes + + * Tabs component is supported again + + * **Test Push In the Simulator** – The simulator now supports [testing push notification](https://www.codenameone.com/blog/meltdown-updates.html) + +There are many other features both big and small. Check out our [blog](https://www.codenameone.com/blog/) and the github [project history](https://github.com/codenameone/CodenameOne/commits/master). + +### Lowlights + +As we always do with a release we’d like to shine a spotlight on the things this version could do better and the things the next version can improve. Overall we are thrilled with this release but here are a few things we can do better: + + * On device debugging – I wasn’t optimistic about getting this out for 4.0 and I’m still not optimistic about 5.0. We already have a lot on our plate for 5.0 and this is a huge feature + + * Improved default themes & material design – we did a lot of work on the skins but didn’t move the native theme or make a separate material design theme. We need to do a lot of work on the default hello world applications to make them look great out of the door. + +Overall while we implemented a lot of features in 4.0 we didn’t really address most of the problems we highlighted in this section when 3.8 was released. I’m not sure if we have enough time in the 5.0 cycle to improve that but hopefully we can at least move theming more aggressively again. + +### Onwards to 5.0 – Social + +The 5.0 release cycle is relatively short & we already have a lot of things planned for it. + +We should have the new social app tutorial in the [Codename One Academy](https://codenameone.teachable.com/) which will cover cloning Facebook. + +Check out our [survey results](https://www.codenameone.com/blog/survey-results-2018.html) to see the future apps we’ll release into the academy. Even if you never plan to signup to the academy this should be interesting as it gives you a good notion of what can be built with Codename One. + +Other than that we’ll try to launch better docs and designs. We’ve put a lot of effort into improving our design capabilities and one of the big things we’d like to pick up again is app templates. In the past we released a few free themes as Codename One stubs. We’d like to do that again so developers can start from “something”. + +### We Need your Help + +If you think we are doing a good job and appreciate our help please help us by: + + * [Spreading the word](https://www.codenameone.com/blog/how-you-can-help-spread-codenameone.html) + + * [Edit our docs](https://www.codenameone.com/blog/tip-edit-docs-fun-profit.html) + + * [Edit our sources and submit bug fixes](https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html) + + * Or just sign up for enterprise accounts which literally keep the lights on here…​ If your company can afford it please take the time and upgrade to enterprise, this will allow us to work on the things that are important for your company! + +Thanks for reading this far and if you have any thoughts/suggestions of any kind please let us know! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Dalvik** — March 20, 2018 at 10:58 am ([permalink](https://www.codenameone.com/blog/codename-one-4-0-taxi-live.html#comment-23631)) + +> Congratulations, I hadn’t noticed half of these features as they went in 😉 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-4-0-taxi-live.html) + + +### **Bluewater** — March 22, 2018 at 6:05 am ([permalink](https://www.codenameone.com/blog/codename-one-4-0-taxi-live.html#comment-24138)) + +> Nice work! Were any of the deprecated APIs removed or is 4.0 fully backward compatible with 3x code? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-4-0-taxi-live.html) + + +### **Shai Almog** — March 22, 2018 at 8:43 am ([permalink](https://www.codenameone.com/blog/codename-one-4-0-taxi-live.html#comment-23817)) + +> Shai Almog says: +> +> Thanks! +> It should be compatible. We didn’t remove any deprecated API’s but there are changes and some things can always break. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-4-0-taxi-live.html) + + +### **Ross Taylor** — March 31, 2018 at 10:31 am ([permalink](https://www.codenameone.com/blog/codename-one-4-0-taxi-live.html#comment-23743)) + +> Ross Taylor says: +> +> Towards around 1:57 – 59 of the video, I notice a slight flicker of the menu when displayed over the map. Is this a problem of the Google Map you were referring? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-4-0-taxi-live.html) + + +### **Shai Almog** — April 1, 2018 at 4:07 am ([permalink](https://www.codenameone.com/blog/codename-one-4-0-taxi-live.html#comment-23724)) + +> Shai Almog says: +> +> That’s related to the incoming animation. I used a background painter in one of the elements and I think I have an issue in that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-4-0-taxi-live.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-5-0-social-live.md b/docs/website/content/blog/codename-one-5-0-social-live.md new file mode 100644 index 0000000000..1b3d0f336b --- /dev/null +++ b/docs/website/content/blog/codename-one-5-0-social-live.md @@ -0,0 +1,166 @@ +--- +title: Codename One 5.0 "Social" is now Live +slug: codename-one-5-0-social-live +url: /blog/codename-one-5-0-social-live/ +original_url: https://www.codenameone.com/blog/codename-one-5-0-social-live.html +aliases: +- /blog/codename-one-5-0-social-live.html +date: '2018-09-18' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-5-0-social-live/codenameone-5-release-banner.jpg) + +We are thrilled to announce the release of [Codename One](https://www.codenameone.com/) 5.0 – Social. Codename One is an open source “Write Once Run Anywhere” mobile platform for Java and Kotlin developers! +We postponed the release of this version since it’s so packed with big changes. We made CSS a first class citizen in Codename One and made CSS updates live (no recompile necessary). We moved from screenshots in iOS launches to storyboards. Added support for newer JDK’s. Migrated to Android API level 27. Moved our entire build server infrastructure. Redid push notification and so much more…​ + +There is SO MUCH more, check out the details below. + +However if you are new to Codename One here’s a short primer. Codename One is the only platform that…​ + + * Has **Write Once Run Anywhere** with no special hardware requirements and 100% code reuse + + * Compiles **Java** or **Kotlin** into native code for iOS, UWP (Universal Windows Platform), Android & even JavaScript + + * Is **Open Source & Free for commercial use** with an enterprise grade commercial support + + * Is Easy to use with **100% portable Drag & Drop GUI builder** + + * Has Full access to underlying native OS capabilities using the **native** OS programming language (e.g. Objective-C) without compromising portability + + * Has full **control over every pixel** on the screen! Just override paint and draw or use a glass pane to draw anywhere…​ + + * Lets you **use native widgets (views) and mix them with Codename One components** within the same hierarchy (heavyweight/lightweight mixing) + + * Supports **seamless Continuous Integration** out of the box + +To learn more about Codename One check out the [about page](https://www.codenameone.com/about.html) you can [download it for free right now](https://www.codenameone.com/download.html). + +Version 5.0 is nicknamed Social because of the Facebook Clone application that was developed with it for [the online course](https://codenameone.teachable.com/p/build-real-world-full-stack-mobile-apps-in-java) in the Codename One Academy. + +![Facebook Native App vs. our Clone](/blog/codename-one-5-0-social-live/login-screen-original-vs-clone-portrait.png) + +Figure 1. Facebook Native App vs. our Clone + +### Highlights of this Release + +The top 5 features of this release are covered in this short video, check out further details below…​ + + * **Live CSS Update** — CSS is now deeply and seamlessly integrated into Codename One. When you change the content of a CSS file and save the Codename One simulator [automatically updates on the fly](https://www.codenameone.com/blog/live-css-update.html) + + * **Rich Push Notifications** — Push notification was overhauled, we moved the last of the functionality from GCM to FCM. We now support [rich push notifications](https://www.codenameone.com/blog/tich-push-notification-improved-validation.html) that can include images and complex functionality + + * **Launch Screen Storyboards** — Historically iOS used screenshots of apps to fake fast application launches. Codename One automated that process in the past, it’s now discoraged by newer iOS features such as side-by-side multi-tasking. As such we now use [storyboard launch files](https://www.codenameone.com/blog/version-4-1-launch-screen-storyboards.html). This allows side-by-side multi-tasking and as a bonus speeds up compilation while reducing the app size further + + * **New JDK/OpenJDK** Support — [We now support JDK’s 8 to 11](https://www.codenameone.com/blog/uber-book-is-out-jdk-11.html) this includes OpenJDK + + * **New Cloud Servers** — We [migrated the last remaining Codename One servers off of Google App Engine](https://www.codenameone.com/blog/new-build-cloud.html). This allowed us to introduce great new features such as [the ability to increase your free build quota](https://www.codenameone.com/blog/increase-your-build-quotas.html) + + * **Removed Old IDE Preferences UI** — The old right click IDE preferences UI was causing a lot of confusion due to lack of maintenance. It’s [now gone](https://www.codenameone.com/blog/removing-old-preferences.html) and replaced completely by Codename One Settings + + * **Android API Level 27** — We moved to [Android’s API Level 27](https://www.codenameone.com/blog/moving-to-27-facebook-clone-done.html) by default. Since Google requires API level 26 or higher at this time. We’ll probably update API levels faster due to this policy + + * **Lightweight Picker** — The `Picker` component was rewritten as a [lightweight component](https://www.codenameone.com/blog/lightweight-picker-device-detection.html) instead of a native one. This allows far more customization and cross platform consistency for one of our most problematic widgets + + * **Low Level Camera API** — [Camera Kit](https://www.codenameone.com/blog/camerakit-low-level-camera-api.html) allows developers to access the native camera view to grab photos/videos and overlay graphics on top of the camera + + * **Pluggable Spatial SQLite** — [Spatial support for SQLite](https://www.codenameone.com/blog/spatial-pluggable-sqlite.html) lets developers write complex location based applications. This functionality lets developers replace the existing native SQLite implementation with an arbitrary implementation which is very useful for enterprise grade features such as deep encryption, replication etc. + + * **Improved Map Layout** — The map API now includes a [native high performance component layout](https://www.codenameone.com/blog/map-component-positioning-revisited.html) built in + + * **Landscape UIID’s** — Components can [adapt their UIID to landscape](https://www.codenameone.com/blog/ios-back-command-behavior.html), this enables features such as smaller title font/padding in landscape mode + + * **Multiple Smaller Improvements** : + + * [DateUtil API](https://www.codenameone.com/blog/date-util.html) for timezone related date functions + + * Sidemenu [right side option](https://www.codenameone.com/blog/right-sidemenu-tab-order.html) and new tab ordering API + + * Ability to map a list of [property business objects to a table](https://www.codenameone.com/blog/table-property-mapping.html) + + * [Sendgrid cn1lib](https://www.codenameone.com/blog/sendgrid-cn1lib.html) + + * [Rest API overhaul](https://www.codenameone.com/blog/rest-api-error-handling.html) for error handling, properties etc. + + * [On-device webserver](https://www.codenameone.com/blog/on-device-web-server.html) + + * [Auto-reconnect](https://www.codenameone.com/blog/tip-auto-reconnect-web-socket.html) for websockets + +There are many other features both big and small. Check out our [blog](https://www.codenameone.com/blog/) and the github [project history](https://github.com/codenameone/CodenameOne/commits/master). + +### Onwards to 6.0 – Chat + +We took a lot of time for 5.0 and I’d like to take a similar duration for 6.0. I think this made 5.0 a better release. + +We will have a whatsapp clone tutorial in the [Codename One Academy](https://codenameone.teachable.com/). Hence the moniker of the next release. + +Check out our [survey results](https://www.codenameone.com/blog/survey-results-2018.html) to see the future apps we’ll release into the academy. Even if you never plan to signup to the academy this should be interesting as it gives you a good notion of what can be built with Codename One. + +### We Need your Help + +If you think we are doing a good job and appreciate our help please help us by: + + * [Spreading the word](https://www.codenameone.com/blog/how-you-can-help-spread-codenameone.html) + + * [Edit our docs](https://www.codenameone.com/blog/tip-edit-docs-fun-profit.html) + + * [Edit our sources and submit bug fixes](https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html) + + * Or just sign up for enterprise accounts which literally keep the lights on here…​ If your company can afford it please take the time and upgrade to enterprise, this will allow us to work on the things that are important for your company! + +Thanks for reading this far and if you have any thoughts/suggestions of any kind please let us know! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **davidwaf** — September 19, 2018 at 9:10 pm ([permalink](https://www.codenameone.com/blog/codename-one-5-0-social-live.html#comment-23928)) + +> Awesome work!! ..as always. Push notifications: there was a mention they will be eventually available even for basic accounts? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-5-0-social-live.html) + + +### **Shai Almog** — September 20, 2018 at 6:50 am ([permalink](https://www.codenameone.com/blog/codename-one-5-0-social-live.html#comment-24029)) + +> Shai Almog says: +> +> Thanks! +> +> Our general thought is to enable a small amount monthly push messages for free/basic users (e.g. 100) so they can test push functionality when building the app. The idea is to upgrade to pro only if they find push useful. +> +> Another idea is to increase the quota based on referrals so even the free tier would be able to get enough push messages for a small app. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-5-0-social-live.html) + + +### **Lukman Javalove Idealist Jaji** — September 20, 2018 at 1:04 pm ([permalink](https://www.codenameone.com/blog/codename-one-5-0-social-live.html#comment-22646)) + +> Lukman Javalove Idealist Jaji says: +> +> I was gon ask the same question… Is there a timeline as to when this 100 units will be available? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-5-0-social-live.html) + + +### **Shai Almog** — September 25, 2018 at 8:20 am ([permalink](https://www.codenameone.com/blog/codename-one-5-0-social-live.html#comment-24013)) + +> Shai Almog says: +> +> No. This depends on two things: +> – Is it worth our while +> – Do we have the resources to do the required work (which is extensive) +> +> Currently both are no. So far we don’t see any noticeable impact from the referral program. So investing more time in this probably won’t drive traction. We have a lot on our plates for the end of the year and Q1 2019 so I don’t see this happening soon. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-5-0-social-live.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-6-0-chat-live.md b/docs/website/content/blog/codename-one-6-0-chat-live.md new file mode 100644 index 0000000000..6d2d8da4f2 --- /dev/null +++ b/docs/website/content/blog/codename-one-6-0-chat-live.md @@ -0,0 +1,110 @@ +--- +title: Codename One 6.0 "Chat" is now Live +slug: codename-one-6-0-chat-live +url: /blog/codename-one-6-0-chat-live/ +original_url: https://www.codenameone.com/blog/codename-one-6-0-chat-live.html +aliases: +- /blog/codename-one-6-0-chat-live.html +date: '2019-02-26' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-6-0-chat-live/codenameone-6-release-banner.jpg) + +We are thrilled to announce the release of [Codename One](https://www.codenameone.com/) 6.0 – Chat. Codename One is an open source “Write Once Run Anywhere” mobile platform for Java and Kotlin developers! +With this release we introduced [Codename One Build](https://cloud.codenameone.com/buildapp/index.html) which is one of the biggest overhauls to the Codename One workflow since its inception. We also refined and updated many underlying technologies e.g. the xcode 10.1 migration, `WKWebView` support, push replies, badges on Android and much more. + +You can check out the details below for the full review but first if you are new to Codename One here’s a short primer. Codename One is the only platform that: + + * Has **Write Once Run Anywhere** with no special hardware requirements and 100% code reuse + + * Compiles **Java** or **Kotlin** into native code for iOS, UWP (Universal Windows Platform), Android & even JavaScript + + * Is **Open Source & Free for commercial use** with an enterprise grade commercial support + + * Is Easy to use with **100% portable Drag & Drop GUI builder** + + * Has Full access to underlying native OS capabilities using the **native** OS programming language (e.g. Objective-C) without compromising portability + + * Has full **control over every pixel** on the screen! Just override paint and draw or use a glass pane to draw anywhere…​ + + * Lets you **use native widgets (views) and mix them with Codename One components** within the same hierarchy (heavyweight/lightweight mixing) + + * Supports **seamless Continuous Integration** out of the box + +To learn more about Codename One check out the [about page](https://www.codenameone.com/about.html) you can [download it for free right now](https://www.codenameone.com/download.html). + +Version 6.0 is nicknamed Chat because of the WhatsApp Clone application that was developed with it for [the online course](https://codenameone.teachable.com/p/build-real-world-full-stack-mobile-apps-in-java) in the Codename One Academy. + +### Highlights of this Release + +The top 5 features of this release are covered in this short video, check out further details below…​ + + * **Codename One Build** — we can now monitor builds from [Android](https://play.google.com/store/apps/details?id=com.codename1.build.app) and [iOS](https://www.codenameone.com/blog/build-app-on-ios.html). The app is also available for every device through [web PWA](https://cloud.codenameone.com/buildapp/index.html). It works with push notification and is built with Codename One! + +__ | Currently the iOS version is still in beta due to the tedious appstore approval process +---|--- + + * **xcode 10.1 Migration** — builds on the Codename One cloud implicitly use [xcode 10.1](https://www.codenameone.com/blog/xcode-10-1-migration-phase-2.html). We migrated from xcode 9.2 to satisfy Apples requirements, this has been seamless for [the most part](https://www.codenameone.com/blog/file-chooser-xcode-10.html) + + * **VM Changes** — we now support `java.util.Objects` and some additional [methods from Class](https://www.codenameone.com/blog/vm-enhancments-full-screen-xml.html) + + * **New Switch API** — [Switch](https://www.codenameone.com/blog/switch-progress-pull.html) replaces the old `OnOffSwitch` API which is pretty old by now + + * **Reply Push Notifications** — the final piece of [RFE 2208 Rich Push Notifications](https://github.com/codenameone/CodenameOne/issues/2208) is now [implemented](https://www.codenameone.com/blog/rich-push-notification-improved.html). You can now prompt a user for a reply via a push message + + * **Support for Badges on Android** — we can now mark an Android icon with a [numeric badge](https://www.codenameone.com/blog/validate-owner-badges-imageviewer-picker-range.html) + + * **Material Design Infinite Progress** — [InfiniteProgress](https://www.codenameone.com/blog/switch-progress-pull.html) now has a material design mode that includes the custom circle animation we see in material design + + * **WKWebView Support** — Apple includes two implementations of a “WebView”. We now support [both](https://www.codenameone.com/blog/wkwebview.html) + + * **CSS Improvements** — underline border is now [supported natively](https://github.com/codenameone/CodenameOne/commit/b6a85e5c8ab161405a18d51871b48df43744e806). Round rectangle is also [supported natively](https://github.com/codenameone/CodenameOne/commit/66c87a6f2896bed0b1ed2834860b230e4ec8648f) and lets you activate the angle only on [specific corners](https://github.com/codenameone/CodenameOne/commit/52172ba9297ccfefaeb9497fae39b3360edeea5d) as per [this RFE](https://github.com/codenameone/CodenameOne/issues/2350) + + * **Picker Improvements** — `Picker` now lets you define [start/end date](https://github.com/codenameone/CodenameOne/issues/2573) + + * **FontImage rotateAnimation** — `FontImage` lets you animate an icon so it [rotates infinitely](https://www.codenameone.com/blog/validation-regex-masking.html) effectively making every component into an `InfiniteProgress` + + * **Added Ownership to Component Hierarchy** — [ownership](https://www.codenameone.com/blog/validate-owner-badges-imageviewer-picker-range.html) allows us to create a relationship between components other than `Component` → `Container` + + * **Added Animation Safe Revalidate** — `revalidte()` is a powerful tool but if it’s invoked when an animation is in progress it might produce unpredictable behavior. [This method](https://www.codenameone.com/blog/validate-owner-badges-imageviewer-picker-range.html) solves that problem + + * **Button Lists** — [List is discouraged](https://www.codenameone.com/blog/avoiding-lists.html) but we still want lists that use a model to represent buttons, radio buttons and checkboxes [button lists](https://www.codenameone.com/blog/button-lists.html) can fit in that niche + + * **XML Mapping in Properties** — this is still an experimental feature but [XML parsing/generating](https://www.codenameone.com/blog/vm-enhancments-full-screen-xml.html) is now supported for `PropertyBusinessObject` + + * **PWA Install Prompt** — a new API lets us [install PWA’s](https://www.codenameone.com/blog/install-home-screen.html) directly + + * **New Full Screen API** — the Desktop and JavaScript targets allow running the app in full screen mode by leveraging this [new API](https://www.codenameone.com/blog/vm-enhancments-full-screen-xml.html) + + * **Facebook SDK Updated** — we updated the Facebook SDK to use the [latest version](https://github.com/codenameone/CodenameOne/issues/2641) + +There are many other features both big and small. Check out our [blog](https://www.codenameone.com/blog/) and the github [project history](https://github.com/codenameone/CodenameOne/commits/master). + +### Onwards to 7.0 – Video + +We took a lot of time for 6.0 but I’m not sure if that’s enough. We might take longer to deliver 7.0. Currently the timeline is unchanged but we’ll have to see. + +We will have a Netflix clone tutorial in the [Codename One Academy](https://codenameone.teachable.com/). Hence the moniker of the next release. + +### We Need your Help + +If you think we are doing a good job and appreciate our help please help us by: + + * [Spreading the word](https://www.codenameone.com/blog/how-you-can-help-spread-codenameone.html) + + * [Edit our docs](https://www.codenameone.com/blog/tip-edit-docs-fun-profit.html) + + * [Edit our sources and submit bug fixes](https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html) + + * Or just sign up for enterprise accounts which literally keep the lights on here…​ If your company can afford it please take the time and upgrade to enterprise, this will allow us to work on the things that are important for your company! + +Thanks for reading this far and if you have any thoughts/suggestions of any kind please let us know! + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-article-in-sdj.md b/docs/website/content/blog/codename-one-article-in-sdj.md new file mode 100644 index 0000000000..d91b68f7ea --- /dev/null +++ b/docs/website/content/blog/codename-one-article-in-sdj.md @@ -0,0 +1,50 @@ +--- +title: Codename One Article In SDJ +slug: codename-one-article-in-sdj +url: /blog/codename-one-article-in-sdj/ +original_url: https://www.codenameone.com/blog/codename-one-article-in-sdj.html +aliases: +- /blog/codename-one-article-in-sdj.html +date: '2013-08-19' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-article-in-sdj/codename-one-article-in-sdj-1.jpg) + + + + +[ +![SDJ](/blog/codename-one-article-in-sdj/codename-one-article-in-sdj-1.jpg) +](http://sdjournal.org/game-development-how-to-become-a-millionaire-teaser-download-for-free/) + + + +Remember the +[ +Poker app we teased a couple of weeks ago +](http://www.codenameone.com/3/post/2013/08/you-can-bet-on-it.html) +? + + +Now you can +[ +read all about it in SDJ, the entire article is in the downloadable PDF +](http://sdjournal.org/game-development-how-to-become-a-millionaire-teaser-download-for-free/) +(please buy the magazine!). + + +We’ll try to post the full source code into SVN and get into more details about it here. If you have any questions/comments related to the article feel free to ask in the comments section right here. + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-benchmarked-with-amazing-results.md b/docs/website/content/blog/codename-one-benchmarked-with-amazing-results.md new file mode 100644 index 0000000000..28aafcf133 --- /dev/null +++ b/docs/website/content/blog/codename-one-benchmarked-with-amazing-results.md @@ -0,0 +1,44 @@ +--- +title: Codename One Benchmarked With Amazing Results +slug: codename-one-benchmarked-with-amazing-results +url: /blog/codename-one-benchmarked-with-amazing-results/ +original_url: https://www.codenameone.com/blog/codename-one-benchmarked-with-amazing-results.html +aliases: +- /blog/codename-one-benchmarked-with-amazing-results.html +date: '2012-12-06' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-benchmarked-with-amazing-results/codename-one-benchmarked-with-amazing-results-1.png) + + + + +[ +![Picture](/blog/codename-one-benchmarked-with-amazing-results/codename-one-benchmarked-with-amazing-results-1.png) +](/img/blog/old_posts/codename-one-benchmarked-with-amazing-results-large-2.png) + +[ +Steve Hannah +](http://sjhannah.com/blog/) +who ported Codename One to Avian has just completed a set of benchmarks on Codename One’s iOS performance putting Codename One’s at 33% slower performance than native C and faster performance than Objective-C! + +I won’t spoil his research results so please read his full post +[ +here +](http://sjhannah.com/blog/?p=226) +. + +A small disclaimer is that the Objective-C benchmark is a bit heavy on the method/message calls which biases the benchmark in our favor. Method invocations in Codename One are naturally much faster than the equivalent Objective-C code due to the semantics of that language. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-charts.md b/docs/website/content/blog/codename-one-charts.md new file mode 100644 index 0000000000..591007de82 --- /dev/null +++ b/docs/website/content/blog/codename-one-charts.md @@ -0,0 +1,460 @@ +--- +title: Codename One Charts +slug: codename-one-charts +url: /blog/codename-one-charts/ +original_url: https://www.codenameone.com/blog/codename-one-charts.html +aliases: +- /blog/codename-one-charts.html +date: '2015-02-03' +author: Steve Hannah +--- + +![Header Image](/blog/codename-one-charts/codename-one-charts-1.png) + + + + + +![Picture](/blog/codename-one-charts/codename-one-charts-1.png) + + + + + + +This post was written by +[ +Steve Hannah +](http://sjhannah.com/) +, one of the newest additions to the Codename One team and a long time community contributor. + +The upcoming update to Codename One will include a new package (com.codename1.charts) for rendering charts in your applications. This includes models and renderers for many common classes of charts including many flavours of bar charts, line charts, scatter charts, and pie charts. + +** +Goals +** + +For the charts package, we wanted to enable Codename One developers to add charts and visualizations to their apps without having to include external libraries or embedding web views. We also wanted to harness the new features in the graphics pipeline to maximize performance. + +Differences from CN1aChartEngine + +This package is based on the existing +[ +CN1aChartEngine library +](https://github.com/shannah/CN1aChartEngine) +, but has been refactored substantially to reduce its size, improve its performance, and simplify its API. If you have used the existing CN1aChartEngine library, much of the API (e.g. models and renderers) will be familiar. The key differences are: + + + + + 1. +** +API +** +. It includes ChartComponent, a first-class Codename One Component that can be included anywhere inside your forms. CN1aChartEngine used a number of Android-like abstractions (e.g. View, Intent, and Activity) to simplify the porting process from the original Android library. While this indeed made it easier to port, it made the API a little bit confusing for Codename One development. + + + + + 2. +** +Performance +** +. It uses the built-in Codename One graphics pipeline for rendering all graphics. CN1aChartEngine used the CN1Pisces library for rendering graphics, which is an order of magnitude slower than the built-in pipeline. This was for historical reasons. When CN1aChartEngine was first developed, the built-in pipeline was missing some features necessary to implement charts. + + + + + +** +Note +** +: +_ +Actually, just before refactoring CN1aChartEngine to produce the charts package, I ported it over to use the built-in pipeline. If you are already using CN1aChartEngine in your app, and want to benefit from the improved performance without having to change your code, you can update to +[ +that version +](https://github.com/shannah/CN1aChartEngine/releases/tag/2.0) +. + +_ + +** +Device Support +** + +Since the charts package makes use of 2D transformations and shapes, it requires some of the new graphics features that are not yet available on all platforms. Currently the following platforms are supported: + + + 1. +Simulator + + + + + 2. +Android + + + + + 3. +iOS + + + + + +If you require support for other platforms, you may want to use the +[ +CN1aChartEngine +](https://github.com/shannah/CN1aChartEngine) +library instead. + +** +Features +** + + 1. +Built-in support for many common types of charts including bar charts, line charts, stacked charts, scatter charts, pie charts and more. + + + + + 2. +Pinch Zoom – The ChartComponent class includes optional pinch zoom support. + + + + + 3. +Panning Support – The ChartComponent class includes optional support for panning. + + + +** +Chart Types +** + +The com.codename1.charts package includes models and renderers for many different types of charts. It is also extensible so that you can add your own chart types if required. The following screen shots demonstrate a small sampling of the types of charts that can be created. + + +* * * + +[ +![](/blog/codename-one-charts/codename-one-charts-2.png) +](/img/blog/old_posts/codename-one-charts-large-14.png) + +[ +![](/blog/codename-one-charts/codename-one-charts-3.png) +](/img/blog/old_posts/codename-one-charts-large-15.png) + +[ +![](/blog/codename-one-charts/codename-one-charts-4.png) +](/img/blog/old_posts/codename-one-charts-large-16.png) + +[ +![](/blog/codename-one-charts/codename-one-charts-5.png) +](/img/blog/old_posts/codename-one-charts-large-17.png) + +[ +![](/blog/codename-one-charts/codename-one-charts-6.png) +](/img/blog/old_posts/codename-one-charts-large-18.png) + +[ +![](/blog/codename-one-charts/codename-one-charts-7.png) +](/img/blog/old_posts/codename-one-charts-large-19.png) + +[ +![](/blog/codename-one-charts/codename-one-charts-8.png) +](/img/blog/old_posts/codename-one-charts-large-20.png) + +[ +![](/blog/codename-one-charts/codename-one-charts-9.png) +](/img/blog/old_posts/codename-one-charts-large-21.png) + +[ +![](/blog/codename-one-charts/codename-one-charts-10.png) +](/img/blog/old_posts/codename-one-charts-large-22.png) + +[ +![](/blog/codename-one-charts/codename-one-charts-11.png) +](/img/blog/old_posts/codename-one-charts-large-23.png) + +[ +![](/blog/codename-one-charts/codename-one-charts-12.png) +](/img/blog/old_posts/codename-one-charts-large-24.png) + +[ +![](/blog/codename-one-charts/codename-one-charts-13.png) +](/img/blog/old_posts/codename-one-charts-large-25.png) + + + + +** +Note +** +: +_ +The above screenshots were taken from the ChartsDemo app. You can start playing with this app now by checking it out from our subversion repository. +_ + +** +How to Create A Chart +** + +Adding a chart to your app involves four steps: + + + 1. +** +Build the model +** +. You can construct a model (aka data set) for the chart using one of the existing model classes in the com.codename1.charts.models package. Essentially, this is just where you add the data that you want to display. + + + + + 2. +** +Set up a renderer +** +. You can create a renderer for your chart using one of the existing renderer classes in the com.codename1.charts.renderers package. The renderer allows you to specify how the chart should look. E.g. the colors, fonts, styles, to use. + + + + + 3. +** +Create the Chart View +** +. Use one of the existing view classes in the com.codename1.charts.views package. + + + + + 4. +** +Create a ChartComponent +** +. In order to add your chart to the UI, you need to wrap it in a ChartComponent object. + + + + + +You can check out the +[ +ChartsDemo +](https://code.google.com/p/codenameone/source/browse/#svn%2Ftrunk%2FDemos%2FChartsDemo) +app for specific examples, but here is a high level view of some code that creates a Pie Chart. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — February 5, 2015 at 2:46 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-21800)) + +> Anonymous says: +> +> this is a great addition to the product. Are the charts clickable .. can i drill down? like if i want to drill down into a particular pie in the pie chart and render some other detail, can i do so ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Anonymous** — February 6, 2015 at 2:07 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-22101)) + +> Anonymous says: +> +> The charts are clickable just like any component in Codename One. You can enable pinch zoom and panning by enabling flags on the component. In addition, you can derive the component and override the seriesPressed() and/or seriesReleased() methods to handle clicks on particular series in the chart. These methods receive events that tell you what part of the series was interacted with. +> +> If you wanted to create interactivity, you could use these events to modify the data model, then repaint the component. You could also use Codename One’s animation plumbing to do these things in a smooth transition. +> +> I’ll be writing more about this in future posts. If there are particular things you’d like to see in the posts, please let me know and I’ll try to incorporate them. +> +> Steve +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Anonymous** — February 6, 2015 at 6:02 pm ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-22336)) + +> Anonymous says: +> +> Can we use these library file in Intellij also ? Is so, do I have to just put them in the lib folder of the project ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Anonymous** — February 6, 2015 at 6:13 pm ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-22206)) + +> Anonymous says: +> +> The new charts API is part of the codename one core. No need for libraries. The old chart engine libraries will work in IntelliJ also. Yes just place the cn1lib files in your lib directory and select “Refresh libs”. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **manezi** — May 18, 2015 at 9:56 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-22319)) + +> manezi says: +> +> Thanks for the great work. Is additional platform support likely to be offered any time soon for com.codename1.charts? Or are platform limitations preventing this? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Shai Almog** — May 18, 2015 at 3:28 pm ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-22392)) + +> Shai Almog says: +> +> It also works on the JavaScript port now. +> Which platforms are you interested in? +> It works on all of our supported platforms except for J2ME, RIM and Windows Phone. J2ME & RIM are pretty outdated and irrelevant by now. We will probably rewrite the Windows work on top of their upcoming Android support at which point we we will have full support for charts. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Sana Maghraoui** — December 24, 2016 at 9:32 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-23294)) + +> Sana Maghraoui says: +> +> hello! I’m trying to do run this charts but I’m not able can u help me please? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Shai Almog** — December 25, 2016 at 8:14 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-23067)) + +> Shai Almog says: +> +> Hi, +> what isn’t working? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Sana Maghraoui** — December 25, 2016 at 5:15 pm ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-24118)) + +> Sana Maghraoui says: +> +> hello! +> +> I downloaded the project chart_master but it’s unrunnable +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Shai Almog** — December 26, 2016 at 5:06 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-22838)) + +> Shai Almog says: +> +> It’s a bit hard to setup a new project for first timers. That’s why we have this demo in the new menu of intellij and NetBeans. Just create a new demo project and it should be one of the options. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Sana Maghraoui** — December 26, 2016 at 8:37 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-23096)) + +> Sana Maghraoui says: +> +> hi! +> It’s okay I made it but It’s static can I make it dynamic? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Sana Maghraoui** — December 26, 2016 at 1:57 pm ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-23231)) + +> Sana Maghraoui says: +> +> hello I need to make dynamic charts can you help me? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Shai Almog** — December 27, 2016 at 6:24 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-23208)) + +> Shai Almog says: +> +> There is a dynamic chart in the demo as well as in the kitchen sink demo (under sales) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Sana Maghraoui** — December 27, 2016 at 9:53 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-24122)) + +> Sana Maghraoui says: +> +> I mean with dynamic that get information from the DataBase and display it +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Sana Maghraoui** — December 27, 2016 at 10:02 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-23062)) + +> Sana Maghraoui says: +> +> *please help me I need to get information from the database and to display it +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Shai Almog** — December 28, 2016 at 1:23 pm ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-23175)) + +> Shai Almog says: +> +> Kitchen sink gets information from a UI table, getting it from a database or a UI table is similar. External source that refreshes the table. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Sana Maghraoui** — December 28, 2016 at 10:04 pm ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-23037)) + +> Sana Maghraoui says: +> +> thank you for your replies but I can’t adapt the project to the one I working with I need help .I’m not finding the Myapplication .java in the kitchenSkin in the Demo so how can I do?thank you for your help +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Shai Almog** — December 29, 2016 at 5:51 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-22688)) + +> Shai Almog says: +> +> Kitchen sink has files that are named differently (pretty much all apps/demos do), this specific demo has that code in the SalesDemo. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Jared Ruplinger** — October 9, 2017 at 3:05 pm ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-23646)) + +> Jared Ruplinger says: +> +> For those who are having trouble following the examples in the demo linked from this post, you might want to check out the “newer” demo from the post at [https://www.codenameone.com…]() +> +> It is a smidge simpler. That aside, however, there are a lot of moving pieces to the charts functionality and it would sure be nice to have some more thorough documentation. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + + +### **Shai Almog** — October 10, 2017 at 4:40 am ([permalink](https://www.codenameone.com/blog/codename-one-charts.html#comment-23638)) + +> Shai Almog says: +> +> Yes, I agree. We need simpler charts. We added some simpler code into the kitchen sink under the sales demo. It tries to demonstrate a more “real world” use case. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-charts.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-control-center-desktop-app.md b/docs/website/content/blog/codename-one-control-center-desktop-app.md new file mode 100644 index 0000000000..6dc2cd687c --- /dev/null +++ b/docs/website/content/blog/codename-one-control-center-desktop-app.md @@ -0,0 +1,117 @@ +--- +title: Codename One Control Center Desktop App +slug: codename-one-control-center-desktop-app +url: /blog/codename-one-control-center-desktop-app/ +original_url: https://www.codenameone.com/blog/codename-one-control-center-desktop-app.html +aliases: +- /blog/codename-one-control-center-desktop-app.html +date: '2020-12-29' +author: Chen Fishbein +--- + +We have recently released a new tool named Control Center. Some of you may ask why have we released a new tool? You already have quite a few: IDE plugins, builds dashboard, preferences app, simulator, designer, GUI builder and more. + +### Why? + +Well the main reason behind this new app is exactly because we have plenty of tools. + +The new Control Center App’s aim is to consolidate the many tools we have which will make your life easier and ours much easier to release updates and to introduce new features and support. + +### What’s in it? + +The first version we are releasing contains the preferences app, the builds dashboard and the support channel. Moving forward we plan to enhance it and move more of the tools into this App. + +Please feel free to send us feedback and suggestions how to improve + +Happy coding! and a Happy New Year! + +### Screenshots + +![](/blog/codename-one-control-center-desktop-app/cc1-1024x616.png) ![](/blog/codename-one-control-center-desktop-app/cc2-1024x640.png) ![](/blog/codename-one-control-center-desktop-app/cc3-1024x640.png) +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — December 31, 2020 at 3:35 pm ([permalink](https://www.codenameone.com/blog/codename-one-control-center-desktop-app.html#comment-24369)) + +> Francesco Galgani says: +> +> Happy New Year to all Codename One staff and developers! +> +> Codename One has become an important part of my life for years now… I wish all of us developers to realize our dreams. +> +> Happy 2021! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-control-center-desktop-app.html) + + +### **Javier Anton** — January 10, 2021 at 9:42 pm ([permalink](https://www.codenameone.com/blog/codename-one-control-center-desktop-app.html#comment-24375)) + +> Javier Anton says: +> +> A bit late, but happy new year to you too Francesco. CN1 has also dug a hole in my heart, here’s to a great 2021 for all developers and of course for CN1! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-control-center-desktop-app.html) + + +### **Javier Anton** — January 11, 2021 at 6:32 pm ([permalink](https://www.codenameone.com/blog/codename-one-control-center-desktop-app.html#comment-24376)) + +> Javier Anton says: +> +> I can’t click on the “Control Center” link. I also can’t find the tool on the website +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-control-center-desktop-app.html) + + +### **Chen Fishbein** — January 12, 2021 at 8:51 am ([permalink](https://www.codenameone.com/blog/codename-one-control-center-desktop-app.html#comment-24377)) + +> Chen Fishbein says: +> +> The “Control Center” App replaces the settings app, it is accessible from the IDE plugins. +> Select the “CodenameOne Settings” from the plugin.(notice if you still see the old settings do an “update” from the Settings app menu and restart the app). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-control-center-desktop-app.html) + + +### **Colin Forster** — March 15, 2021 at 2:21 am ([permalink](https://www.codenameone.com/blog/codename-one-control-center-desktop-app.html#comment-24412)) + +> Colin Forster says: +> +> I can’t login via the Control Center. The Login button responds to the click (as in the button colour changes) but nothing happens. +> Is there any log files I can check which might shed more light? +> +> Linux Mint 20 +> IntelliJ IDEA 2020.3 CE +> +> Let me know if you need any more clarification. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-control-center-desktop-app.html) + + +### **Shai Almog** — March 15, 2021 at 3:34 pm ([permalink](https://www.codenameone.com/blog/codename-one-control-center-desktop-app.html#comment-24413)) + +> Shai Almog says: +> +> Thanks for the headsup. We’ll try to fix it for the next update of the tool. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-control-center-desktop-app.html) + + +### **Colin Forster** — March 17, 2021 at 6:48 am ([permalink](https://www.codenameone.com/blog/codename-one-control-center-desktop-app.html#comment-24415)) + +> Colin Forster says: +> +> I managed to get it working again by re-installing the ide (and therefore cn1 plugin). Thanks for the prompt reply. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-control-center-desktop-app.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-graphics-low-level-animations.md b/docs/website/content/blog/codename-one-graphics-low-level-animations.md new file mode 100644 index 0000000000..e5f8a11c3d --- /dev/null +++ b/docs/website/content/blog/codename-one-graphics-low-level-animations.md @@ -0,0 +1,102 @@ +--- +title: Codename One Graphics – Low Level Animations +slug: codename-one-graphics-low-level-animations +url: /blog/codename-one-graphics-low-level-animations/ +original_url: https://www.codenameone.com/blog/codename-one-graphics-low-level-animations.html +aliases: +- /blog/codename-one-graphics-low-level-animations.html +date: '2015-02-10' +author: Steve Hannah +--- + +![Header Image](/blog/codename-one-graphics-low-level-animations/clock_small.png) + +![](/blog/codename-one-graphics-low-level-animations/clock_small.png) + +In my previous post, I created a static analog clock component. In this post, I will use Codename One’s animation API to update the clock every continually so that it will keep time correctly. + +#### How Animation Works in Codename One + +From the [Developer’s Guide:](http://www.codenameone.com/manual/) + +> The Codename One event dispatch thread has a special animation “pulse” allowing an animation to update its state and draw itself. +> +> Every component in Codename One contains an animate() method that returns a boolean value, you can also implement the Animation interface in an arbitrary component to implement your own animation. In order to receive animation events you need to register yourself within the parent form, it is the responsibility of the parent for to call animate(). +> +> If the animate method returns true then the animation will be painted. It is important to deregister animations when they aren’t needed to conserve battery life. However, if you derive from a component, which has its own animation logic you might damage its animation behavior by deregistering it, so tread gently with the low level API’s.” + +#### Device Support + +The Codename One animation API is a core feature of Codename One and it is supported on all platforms. + +#### Animating the Clock + +In order to animate our clock so that it updates once per second, we only need to do two things: + + 1. Implement the animate() method to indicate when the clock needs to be updated/re-drawn. + 2. Register the component with the form so that it will receive animation “pulses”. + +The animate() method in my AnalogClock class: + + + Date currentTime = new Date(); + long lastRenderedTime = 0; + + @Override + public boolean animate() { + if ( System.currentTimeMillis()/1000 != lastRenderedTime/1000){ + currentTime.setTime(System.currentTimeMillis()); + return true; + } + return false; + } + +This method will be called on each “pulse” of the EDT. It checks the last time the clock was rendered and returns true only if the clock hasn’t been rendered in the current “time second” interval. Otherwise it returns false. This ensures that the clock will only be redrawn when the time changes. + +#### Starting and Stopping the Animation + +Animations can be started and stopped via the Form.registerAnimated(component) and Form.deregisterAnimated(component) methods. I have chosen to encapsulate these calls in start() and stop() methods in my component as follows: + + + public void start(){ + this.getComponentForm().registerAnimated(this); + } + + public void stop(){ + this.getComponentForm().deregisterAnimated(this); + } + +So the code to instantiate the clock, and start the animation would be something like: + + + AnalogClock clock = new AnalogClock(); + parent.addComponent(clock); + clock.start(); + +#### The Final Result + +You can view the full source to this component [here](https://gist.github.com/shannah/d83d30c851b6f746260f). +You may want to compare this to the [static version](https://gist.github.com/shannah/7f6abb8f4e16a5203771) from the +previous post to help identify the parts that are related to animation. + +#### Higher-Level Animations + +This tutorial dealt with the low-level animation API since the focus of this series is on low-level graphics. For most common use-cases, however, Codename One provides higher-level APIs that make it much easier to incorporate animations into your UI. Some examples of these APIs include: + + 1. Transitions between forms. + 2. Animating components when their layouts are changed. + 3. Animating components when their hierarchy is changed. + +See the [Developer’s Guide](http://www.codenameone.com/manual/) for more information about these APIs. + +#### More Advanced Animations + +This tutorial only scratched the surface of what is possible with the Codename One animation API. In a future installment, we will explore the Motion class and see how it can be used to develop more complex animations and UI effects. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-graphics-part-2-drawing-an-analog-clock.md b/docs/website/content/blog/codename-one-graphics-part-2-drawing-an-analog-clock.md new file mode 100644 index 0000000000..b3b6c05844 --- /dev/null +++ b/docs/website/content/blog/codename-one-graphics-part-2-drawing-an-analog-clock.md @@ -0,0 +1,566 @@ +--- +title: 'Codename One Graphics Part 2: Drawing an Analog Clock' +slug: codename-one-graphics-part-2-drawing-an-analog-clock +url: /blog/codename-one-graphics-part-2-drawing-an-analog-clock/ +original_url: https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html +aliases: +- /blog/codename-one-graphics-part-2-drawing-an-analog-clock.html +date: '2015-01-27' +author: Steve Hannah +--- + +![Header Image](/blog/codename-one-graphics-part-2-drawing-an-analog-clock/codename-one-graphics-part-2-drawing-an-analog-clock-1.png) + + + + + +![Codename One Clock](/blog/codename-one-graphics-part-2-drawing-an-analog-clock/codename-one-graphics-part-2-drawing-an-analog-clock-1.png) + + + + + + + + + + + + + + + + + +This post was written by +[ +Steve Hannah +](http://sjhannah.com/) +, one of the newest additions to the Codename One team and a long time community contributor. + +The new Codename One graphics pipeline includes support for advanced 2D and 3D transformations. + +[ +Last time +](http://www.codenameone.com/blog/codename-one-graphics) +I talked about some of the new features in Codename One’s graphics. Then I presented an example app to demonstrate the use of the new shapes API. In this instalment, I will focus on some of the new graphics transformation features. + +** +Background +** + +The Graphics class has included limited support for 2D transformations for some time now including scaling, rotation, and translation: + + + + + + + + + + + + + + + * +scale(x,y) : Scales drawing operations by a factor in each direction. + + * + + * +translate(x,y) : Translates drawing operations by an offset in each direction. + + * + + * +rotate(angle) : Rotates about the origin. + + * + + * +rotate(angle, px, py) : Rotates about a pivot point. + + * + + +Note: scale() and rotate() methods are only available on platforms that support Affine transforms. Currently only Android, iOS and the simulator (JavaSE) support these methods. + +** +Device Support +** + +You can check if a particular Graphics context supports rotation and scaling using the isAffineSupported() method. + +e.g. + +public void paint(Graphics g) { + +if ( g.isAffineSupported() ){ + +// Do something that requires rotation and scaling + +} else { + +// Fallback behaviour here + +} + +} + +** +Example: +** +Drawing an Analog Clock + +In the following sections, I will implement an analog clock component. This will demonstrate three key concepts in Codename One’s graphics: + + + 1. +Using the GeneralPath class for drawing arbitrary shapes. + + + + + 2. +Using Graphics.translate() to translate our drawing position by an offset. + + + + + 3. +Using Graphics.rotate() to rotate our drawing position. + + + + + +There are three separate things that need to be drawn in a clock: + + + 1. +** +The tick marks +** +. E.g. most clocks will have a tick mark for each second, larger tick marks for each hour, and sometimes even larger tick marks for each quarter hour. + + + + + 2. +** +The numbers +** +. We will draw the clock numbers (1 through 12) in the appropriate positions. + + + + + 3. +** +The hands +** +. We will draw the clock hands to point at the appropriate points to display the current time. + + +** +The AnalogClock Component +** + +Our clock will extend the Component class, and override the paintBackground() method to draw the clock as follows: + + +* * * + + +** +Setting up the Parameters +** + +Before we actually draw anything, let’s take a moment to figure out what values we need to know in order to draw an effective clock. Minimally, we need two values: + + + 1. +The center point of the clock. + + + + + 2. +The radius of the clock. + + + + + +In addition, I am adding the following parameters to to help customize how the clock is rendered: + + + 1. +** +The padding +** +(i.e. the space between the edge of the component and the edge of the clock circle. + + + + + 2. +** +The tick lengths +** +. I will be using 3 different lengths of tick marks on this clock. The longest ticks will be displayed at quarter points (i.e. 12, 3, 6, and 9). Slightly shorter ticks will be displayed at the five-minute marks (i.e. where the numbers appear), and the remaining marks (corresponding with seconds) will be quite short. + + + + + + + +** +Drawing the Tick Marks +** + + + +For the tick marks, we will use a single GeneralPath object, making use of the moveTo() and lineTo() methods to draw each individual tick. + + +** +Tip: +** +This example uses a little bit of trigonometry to calculate the (x,y) coordinates of the tick marks based on the angle and the radius. If math isn’t your thing, don’t worry. This example just makes use of the identities: x=r*cosθ and y=r*sinθ. + +For more information about drawing shapes using GeneralPath, I recommend you check out my +[ +previous post on Codename One Graphics +](http://www.codenameone.com/blog/codename-one-graphics) +. + +At this point our clock should include a series of tick marks orbiting a blank center as shown below: + + + +![Picture](/blog/codename-one-graphics-part-2-drawing-an-analog-clock/codename-one-graphics-part-2-drawing-an-analog-clock-2.png) + + +** +Drawing the Numbers +** + +I have seen clocks before that don’t include any actual numbers, but these are far too advanced for my rudimentary clock-reading skills. I want my clock to have numbers on it. Nothing fancy. Just “1” through “12” labelling the appropriate tick marks. + +The Graphics.drawString(str, x, y) method allows you to draw text at any point of a component. The tricky part here is calculating the correct x and y values for each string so that the number appears in the correct location. + +For the purposes of this tutorial, I’m going to use the following strategy. For each number (1 through 12): + + + 1. +Use the Graphics.translate(x,y) method to apply a translation from the clock’s center point to the point where the number should appear. + + + + + 2. +Draw number (using drawString()) at the clock’s center. It should be rendered at the correct point due to our translation. + + + + + 3. +Invert the translation performed in step 1. + + + + + +** +Note: +** +This example is, admittedly, a little contrived to allow for a demonstration of the Graphics.translate() method. We could have just as easily passed the exact location of the number to drawString() rather than draw at the clock center and translate to the correct location. + +Now, we should have a clock with tick marks and numbers as shown below: + + + +![Picture](/blog/codename-one-graphics-part-2-drawing-an-analog-clock/codename-one-graphics-part-2-drawing-an-analog-clock-3.png) + + +** +Drawing the Hands +** + +Our clock will include three hands: Hour, Minute, and Second. I will use a separate GeneralPath object for each hand. For the positioning/angle of each, I will employ the following strategy: + + + 1. +Draw the hand at the clock center pointing toward 12 (straight up). + + + + + 2. +Translate the hand slightly down so that it overlaps the center. + + + + + 3. +Rotate the hand at the appropriate angle for the current time, using the clock center as a pivot point. + + + + + +** +Drawing the Second Hand +** + +For the “second” hand, I will just use a simple line from the clock center to the inside edge of the medium tick mark at the 12 o’clock position. + +GeneralPath secondHand = new GeneralPath(); + +secondHand.moveTo((float)cX, (float)cY); + +secondHand.lineTo((float)cX, (float)(cY-(r-medTickLen))); + +And I will translate it down slightly so that it overlaps the center. This translation will be performed on the GeneralPath object directly rather than through the Graphics context: + +Shape translatedSecondHand = secondHand.createTransformedShape( Transform.makeTranslation(0f, 5) ); + +** +Rotating the Second Hand +** + +The rotation of the second hand will be performed in the Graphics context via the rotate(angle, px, py) method. This requires us to calculate the angle. The px and py arguments constitute the pivot point of the rotation, which, in our case will be the clock center. + +** +Warning: +** +The rotation pivot point is expected to be in absolute screen coordinates rather than relative coordinates of the component. Therefore we need to get the absolute clock center position in order to perform the rotation. + + +** +Note: +** +Remember to call resetAffine() after you’re done with the rotation, or you will see some unexpected results on your form. + +** +Drawing the Minute And Hour Hands +** + +The mechanism for drawing the hour and minute hands is largely the same as for the minute hand. There are a couple of added complexities though: + + + 1. +We’ll make these hands trapezoidal, and almost triangular rather than just using a simple line. Therefore the GeneralPath construction will be slightly more complex. + + + + + 2. +Calculation of the angles will be slightly more complex because they need to take into account multiple parameters. E.g. The hour hand angle is informed by both the hour of the day and the minute of the hour. + + + + + +The remaining drawing code is as follows: + + + + + +** +The Final Result +** + + + + +At this point, we have a complete clock as shown below: + + + + + + + + + +![Picture](/blog/codename-one-graphics-part-2-drawing-an-analog-clock/codename-one-graphics-part-2-drawing-an-analog-clock-4.png) + + +You can view the full source to this component +[ +here +](https://gist.github.com/shannah/7f6abb8f4e16a5203771) +. + +** +Animating the Clock +** + +The current clock component is cool, but it is static. It just displays the time at the point the clock was created. Next time we’ll improve on this by adding animation support so that the clock will “tick” and keep the correct time – just like a real clock. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — January 29, 2015 at 3:48 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-22312)) + +> Anonymous says: +> +> That’s very cool Steve. Semi off-topic, but you might be interested in this JavaFX clock: [http://blog.crisp.se/2012/0…]() – it uses JavaFX bound properties in a very elegant fashion. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **Anonymous** — January 29, 2015 at 4:07 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-22125)) + +> Anonymous says: +> +> As an FYI I created the original properties project that inspired JavaFX properties: [https://java.net/projects/b…]() +> +> This predated my LWUIT work but we didn’t take it into LWUIT due to size concerns… Adding “proper” properties to Codename One is something that has been on my wishlist for quite some time, but to do this properly I would want the VM to support this internally so properties would have zero overhead compared to fields. That would take some effort… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **Anonymous** — January 29, 2015 at 4:23 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-21597)) + +> Anonymous says: +> +> I can blame you ! LOL. I have to admit having used Swing, LWUIT etc for a very long time, then coming to FX with it’s extensive use of binding was quite a shock and hard on my tired old brain – but then when see code like the clock I mentioned, where the binding makes it “just work” with almost no code, you can really see the power of the concept. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **Anonymous** — January 31, 2015 at 7:11 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-22054)) + +> Anonymous says: +> +> Great stuff!! Thanks for this. We need more examples that push CN1 to its limits! +> +> In case some one struggles with showing the clock.. just set the form layout to GridLayout like this: +> +> Form f = new Form(“”); +> +> f.setLayout(new GridLayout(1, 1)); +> +> AnalogClock analogClock = new AnalogClock(); +> +> f.addComponent(analogClock); +> +> f.repaint(); +> +> [f.show](); +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **José Helana** — December 7, 2015 at 8:21 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-22348)) + +> José Helana says: +> +> how do I get the clock to have the time automatically +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **Shai Almog** — December 8, 2015 at 4:47 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-22333)) + +> Shai Almog says: +> +> You can use the java.util.Calendar class to get the current time and set it to the hands. +> See the last section of this tutorial with animating the clock. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **Franck Marchand** — March 3, 2016 at 10:17 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-22691)) + +> Franck Marchand says: +> +> Thanks for this example. +> But do you know why It doesn’t work If I add AnalogClock in Container sets with BoxLayout ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **Shai Almog** — March 4, 2016 at 3:42 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-22525)) + +> Shai Almog says: +> +> Did you override calcPreferredSize() to give the clock a size? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **Franck Marchand** — March 4, 2016 at 1:13 pm ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-22660)) + +> Franck Marchand says: +> +> No, juste: +> +> tb.addCommandToSideMenu(new Command(“Clock2”, theme.getImage(“teams_icn_badgeage_48x48.png”)) { +> @Override +> public void actionPerformed(ActionEvent evt) { +> Form fm = new Form(new BoxLayout(BoxLayout.Y_AXIS)); +> TmAnalogClock clock = new TmAnalogClock(); +> fm.addComponent(clock); +> [fm.show](); +> } +> }); +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **Shai Almog** — March 5, 2016 at 4:13 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-22372)) + +> Shai Almog says: +> +> You need to override the calcPreferredSize() to give the clock a size or invoke setPreferredSize() to hardcode a minimum size. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **Franck Marchand** — March 7, 2016 at 11:54 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-22638)) + +> Franck Marchand says: +> +> Thanks, it works. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **Ahmed Elnabwy** — May 5, 2017 at 6:45 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-21529)) + +> Ahmed Elnabwy says: +> +> imports ,please +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + + +### **Shai Almog** — May 6, 2017 at 5:41 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics-part-2-drawing-an-analog-clock.html#comment-23439)) + +> Shai Almog says: +> +> import com.codename1.ui.*; +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics-part-2-drawing-an-analog-clock.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-graphics-understanding-coordinates.md b/docs/website/content/blog/codename-one-graphics-understanding-coordinates.md new file mode 100644 index 0000000000..6eb617a895 --- /dev/null +++ b/docs/website/content/blog/codename-one-graphics-understanding-coordinates.md @@ -0,0 +1,187 @@ +--- +title: Codename One Graphics – Understanding Coordinates +slug: codename-one-graphics-understanding-coordinates +url: /blog/codename-one-graphics-understanding-coordinates/ +original_url: https://www.codenameone.com/blog/codename-one-graphics-understanding-coordinates.html +aliases: +- /blog/codename-one-graphics-understanding-coordinates.html +date: '2015-02-24' +author: Steve Hannah +--- + +![Header Image](/blog/codename-one-graphics-understanding-coordinates/graphics.jpg) + +![](/blog/codename-one-graphics-understanding-coordinates/graphics.jpg) + +Codename One provides a rich set of drawing primitives in its Graphics class. It allows you to draw text, shapes, and images to the screen. The position where these elements will be rendered is determined based on a combination of Graphics state information (e.g. the current translation, and transform) and coordinates that are passed to the drawing method. Understanding how these coordinates are calculated can be tricky when you first begin using the API. + +Take, for example, the Graphics.drawRect(int x,int y, int width, int height) method. If you are coming to Codename One with fresh eyes, you can probably figure out that this method will draw a width x height rectangle at the coordinate (x,y). However you would probably also want to know exactly what the axes of the coordinate system are. E.g. where is (0,0), and in which directions do x and y get larger. + +#### The Coordinate System + +The Codename One coordinate system follows the example of Swing (and many other – but not all- graphics libraries) and places the origin in the upper left corner of the screen. X-values grow to the right, and Y-values grow downward as illustrated below: + +![The Coordinate System](/blog/codename-one-graphics-understanding-coordinates/coordinate_system.gif) + +Therefore the screen origin is at the top left corner of the screen. Given this information, consider the method call on the Graphics context g: + + + g.drawRect(10,10, 100, 100); + +Where would this rectangle be drawn on the screen? + +If you answered something something like “10 pixels from the top, and 10 pixels from the left of the screen”, you +_might_ be right. It depends on whether the graphics has a translation or transform applied to it. If there is +currently a translation of `(20,20)` (i.e. 20 pixels to the right, and 20 pixels down), then the rectangle would be rendered at `(30, 30)`. + +You can always find out the current translation of the graphics context using the `Graphics.getTranslateX()` and `Graphics.getTranslateY()` methods: + + + // Find out the current translation + int currX = g.getTranslateX(); + int currY = g.getTranslateY(); + + // Reset the translation to zeroes + g.translate(-currX, -currY); + + // Now we are working in absolute screen coordinates + g.drawRect(10, 10, 100, 100); + + // This rectangle should now be drawn at the exact screen + // coordinates (10,10). + + //Restore the translation + g.translate(currX, currY); + +> Note: This example glosses over issues such as clipping and transforms which may cause it to not work as you expect. E.g. When painting a component inside its paint() method, there is a clip applied to the context so that only the content you draw within the bounds of the component will be seen. + +If, in addition, there is a transform applied that rotates the context 45 degrees clockwise, then the rectangle will be drawn at a 45 degree angle with its top left corner somewhere on the left edge of the screen. + +Luckily you usually don’t have to worry about the exact screen coordinates for the things you paint. Most of the time, you will only be concerned with relative coordinates. + +#### Relative Coordinates + +Usually, when you are drawing onto a Graphics context, you are doing so within the context of a Component’s paint() method (or one of its variants). In this case, you generally don’t care what the exact screen coordinates are of your drawing. You are only concerned with their relative location within the coordinate. You can leave the positioning (and even sizing) of the coordinate up to Codename One. + +To demonstrate this, let’s create a simple component called `Rectangle` component, that simply draws a rectangle on the screen. We will use the component’s position and size to dictate the size of the rectangle to be drawn. And we will keep a 5 pixel padding between the edge of the component and the edge of our rectangle. + + + class RectangleComponent extends Component { + public void paint(Graphics g){ + g.setColor(0x0000ff); + g.drawRect(getX()+5, getY()+5, getWidth()-10, getHeight()-10); + } + } + +The result is as follows: + +![Rectangle](/blog/codename-one-graphics-understanding-coordinates/rectangle_component1.png) + +> Note: The `x` and `y` coordinates that are passed to the `drawRect(x,y,w,h)` method are relative to the component’s _parent’s_ origin — **not the component itself .. its parent.** This is why we the _x_ position is `getX()+5` and not just _5_. + +#### Transforms and Rotations + +Unlike the Graphics `drawXXX` primitives, methods for setting transformations, including `scale(x,y)` and `rotate(angle)`, are always applied in terms of screen coordinates. This can be confusing at first, because you may be unsure whether to provide a relative coordinate or an absolute coordinate for a given method. + +The general rule is: + + 1. **All coordinates passed to the drawXXX() and fillXXX() methods will be subject to the graphics context’s transform and translation settings.** + 2. **All coordinates passed to the context’s transformation settings are considered to be screen coordinates, and are not subject to current transform and translation settings.** + +Let’s take our `RectangleComponent` as an example. Suppose we want to rotate the rectangle by 45 degrees, our first attempt might look something like: + + + class RectangleComponent extends Component { + + @Override + protected Dimension calcPreferredSize() { + return new Dimension(250,250); + } + + public void paint(Graphics g) { + g.setColor(0x0000ff); + g.rotate((float) (Math.PI / 4.0)); + g.drawRect(getX() + 5, getY() + 5, getWidth() - 10, getHeight() - 10); + g.rotate(-(float) (Math.PI / 4.0)); + } + }(10,10, 100, 100); + +> Tip: When performing rotations and transformations inside a `paint()` method, always remember to revert your transformations at the end of the method so that it doesn’t pollute the rendering pipeline for subsequent components. + +The behaviour of this rotation will vary based on where the component is rendered on the screen. To demonstrate this, let’s try to place five of these components on a form inside a BorderLayout and see how it looks: + + + class MyForm extends Form { + + public MyForm() { + super("Rectangle Rotations"); + for ( int i=0; i< 10; i++ ){ + this.addComponent(new RectangleComponent()); + } + } + } + +The result is as follows: + +![Rotation](/blog/codename-one-graphics-understanding-coordinates/rotation1.png) + +This may not be an intuitive outcome since we drew 10 rectangle components, be we only see a portion of one rectangle. The reason is that the `rotate(angle)` method uses the screen origin as the pivot point for the rotation. Components nearer to this pivot point will experience a less dramatic effect than components farther from it. In our case, the rotation has caused all rectangles except the first one to be rotated outside the bounds of their containing component - so they are being clipped. A more sensible solution for our component would be to place the rotation pivot point somewhere inside the component. That way all of the components would look the same. Some possibilities would be: + +Top Left Corner: + + + public void paint(Graphics g) { + g.setColor(0x0000ff); + g.rotate((float)(Math.PI/4.0), getAbsoluteX(), getAbsoluteY()); + g.drawRect(getX() + 5, getY() + 5, getWidth() - 10, getHeight() - 10); + g.rotate(-(float) (Math.PI / 4.0), getAbsoluteX(), getAbsoluteY()); + } + +![Rotation](/blog/codename-one-graphics-understanding-coordinates/rotation2.png) + +Center: + + + public void paint(Graphics g) { + g.setColor(0x0000ff); + g.rotate( + (float)(Math.PI/4.0), + getAbsoluteX()+getWidth()/2, + getAbsoluteY()+getHeight()/2 + ); + g.drawRect(getX() + 5, getY() + 5, getWidth() - 10, getHeight() - 10); + g.rotate( + -(float)(Math.PI/4.0), + getAbsoluteX()+getWidth()/2, + getAbsoluteY()+getHeight()/2 + ); + } + +![Rotation](/blog/codename-one-graphics-understanding-coordinates/rotation3.png) + +You could also use the `Graphics.setTransform()` class to apply rotations and other complex transformations (including 3D perspective transforms), but I’ll leave that for its own topic as it is a little bit more complex. + +#### Event Coordinates + +While we’re on the topic of coordinates I would be remiss if I didn’t mention how coordinates are passed in events (e.g. touch events). We saw in [part one of this series](http://www.codenameone.com/blog/codename-one-graphics) that you can listen for touch events on a component by overriding the `pointerPressed(x,y)` method. The coordinates received in this method will be **absolute screen coordinates** , so you may need to do some conversions on these coordinates before using them in your `drawXXX()` methods. + +Recall from part I, that our `pointerPressed()` method looked like: + + + public void pointerPressed(int x, int y) { + addPoint(x-getParent().getAbsoluteX(), y-getParent().getAbsoluteY()); + } + +In this case we translated these points so that they would be relative to the origin of the parent component. This is because the `drawXXX()` methods for this component take coordinates relative to the parent component. + +#### Summary + +Understanding the coordinate system is crucial for obtaining predictable graphics results. When you first begin, you may be unsure of whether a method expects coordinates to be relative to the current component, the parent component, or the screen origin. This post provided a few tips to help navigate the API. In the worst case, you can also just use a bit of trial and error. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-graphics.md b/docs/website/content/blog/codename-one-graphics.md new file mode 100644 index 0000000000..6de4dc29d7 --- /dev/null +++ b/docs/website/content/blog/codename-one-graphics.md @@ -0,0 +1,518 @@ +--- +title: Codename One Graphics +slug: codename-one-graphics +url: /blog/codename-one-graphics/ +original_url: https://www.codenameone.com/blog/codename-one-graphics.html +aliases: +- /blog/codename-one-graphics.html +date: '2015-01-18' +author: Steve Hannah +--- + +![Header Image](/blog/codename-one-graphics/codename-one-graphics-1.jpg) + + + + + + + +![Picture](/blog/codename-one-graphics/codename-one-graphics-1.jpg) + + + + + + + + + +This post we written by +[ +Steve Hannah +](http://sjhannah.com/) +, one of the newest additions to the Codename One team and a long time community contributor. + +This is the first in a series of posts about drawing graphics in Codename One. In this tutorial, we will create a rudimentary drawing app to demonstrate how to use the Shape API. + + + + + + + +* * * + +## +Some Background + + + + + +Codename One has included basic 2D graphics ability since its inception, but until recently, it was missing a few primitives that were required for drawing arbitrary graphics. Most notably, it did not include a general “Shape” API to draw arbitrary paths. This meant that most graphics were composed of images, a few common geometry primitives such as rectangles and circles, and clever use of tiling and clipping. If you wanted to draw an arbitrary shape composed of lines and bezier curves, you were generally out of luck. + + + + + + +I ported the +[ +Pisces graphics library +](https://github.com/shannah/CN1Pisces) +to Codename One last year in order to provide this type of functionality inside Codename One apps. This provided a 2D drawing API, but it was quite slow. Fine for static drawings, but too slow to be used in most animations. + + + + + + +The new CN1 graphics API provides the same types of functionality as the Pisces library, but with drastically improved performance. Finally we can draw complex 2D graphics (and 3D graphics in some platforms) without clogging the rendering pipeline. + + + + + + + + + +## +New Features + + + + + 1. +A Shape API for drawing generalized paths on a Graphics context. + + + + + 2. +A Transformation API to be able to perform transformations on graphics contexts and shapes. (E.g. rotate, scale, translate, etc…​). + + + + + 3. +Support for 3D transformations. (Currently only available on Android and iOS). + + + + +## +Device Support + + + + + +(As of writing, this may change in the future as there is demand to backport the functionality to older platforms). + + + + +API | Simulator | Android | iOS | JME | Windows Phone | BlackBerry +---|---|---|---|---|---|--- +Shapes | Yes | Yes | Yes | – | – | – +2D Transforms | Yes | Yes | Yes | – | – | – +3D Transforms | – | Yes | Yes | – | – | – + +## +A 2D Drawing App + + + + + +Let’s look at a simple example of a drawing app, that allows the user to tap the screen to draw a contour picture. The app will work by simply keeping a +[ +GeneralPath +](/javadoc/com/codename1/ui/geom/GeneralPath.html) +in memory, and continually add points as bezier curves. Whenever a point is added, the path is redrawn to the screen. + + + + +** + + +Step 1: Create a Project +** + +We start by creating a standard “Hello World” project using the “Non-visual” template (i.e. built with code, not the GUI editor). + + + + +** + + +Step 2: Make the Canvas +** + +The center of the app is the DrawingCanvas class, which extends +[ +Component +](/javadoc/com/codename1/ui/Component.html) +. + + + + + + + + +Conceptually this is very basic component. We will be overriding the +[ +paintBackground() +](/javadoc/com/codename1/ui/Component.html#paintBackground%28com.codename1.ui.Graphics%29) +method to draw the path. We keep a reference to a +[ +GeneralPath +](/javadoc/com/codename1/ui/geom/GeneralPath.html) +object (which is the concrete implementation of the Shape interface in Codename One) to store each successive point in the drawing. We also parametrize the stroke width and color. + + + + + + +The implementation of the paintBackground() method (shown above) should be fairly straight forward. It creates a stroke of the appropriate width, and sets the color on the graphics context. Then it calls drawShape() to render the path of points. + + + + + +## +Implementing addPoint() + + + +The addPoint method is designed to allow us to add points to the drawing. A simple implementation that uses straight lines rather than curves might look like this: + + +We introduced a couple house-keeping member vars (lastX and lastY) to store the last point that was added so that we know whether this is the first tap or a subsequent tap. The first tap triggers a moveTo() call, whereas subsequent taps trigger lineTo() calls, which draw lines from the last point to the current point. + + + + + + +A drawing might look like this: + + + + + + + + +![Picture](/blog/codename-one-graphics/codename-one-graphics-2.png) + +## +Using Bezier Curves + + + + + + + + + +Our previous implementation of addPoint() used lines for each segment of the drawing. Let’s make an adjustment to allow for smoother edges by using quadratic curves instead of lines. + +Codename One’s GeneralPath class includes two methods for drawing curves: + + + + + + + + + 1. +[ +quadTo() +](/javadoc/com/codename1/ui/geom/GeneralPath.html#quadTo%28float,%20float,%20float,%20float%29) +: Appends a quadratic bezier curve. It takes 2 points: a control point, and an end point. + + + + + 2. +[ +curveTo() +](/javadoc/com/codename1/ui/geom/GeneralPath.html#curveTo%28float,%20float,%20float,%20float,%20float,%20float%29) +: Appends a cubic bezier curve, taking 3 points: 2 control points, and an end point. + + + + + +See the +[ +General Path javadocs +](/javadoc/com/codename1/ui/geom/GeneralPath.html) +for the full API. + +We will make use of the +[ +quadTo() +](/javadoc/com/codename1/ui/geom/GeneralPath.html#quadTo%28float,%20float,%20float,%20float%29) +method to append curves to the drawing as follows: + + + +This change should be fairly straight forward except, perhaps, the business with the odd variable. Since quadratic curves require two points (in addition to the implied starting point), we can’t simply take the last tap point and the current tap point. We need a point between them to act as a control point. This is where we get the curve from. The control point works by exerting a sort of “gravity” on the line segment, to pull the line towards it. This results in the line being curved. I use the odd marker to alternate the control point between positions above the line and below the line. + + + + + + +A drawing from the resulting app looks like: + + + + + +![Picture](/blog/codename-one-graphics/codename-one-graphics-3.png) + +## +Detecting Platform Support + + + +The DrawingCanvas example is a bit naive in that it assumes that the device supports the shape API. If I were to run this code on a device that doesn’t support the Shape API, it would just draw a blank canvas where I expected my shape to be drawn. You can fall back gracefully if you make use of the +[ +Graphics.isShapeSupported() +](/javadoc/com/codename1/ui/Graphics.html#isShapeSupported%28%29) +method. E.g. + +## +Next Time + + + +The next post in this series will cover 2D animations. Stay tuned for more…​ + + + + + + + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — January 19, 2015 at 8:15 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics.html#comment-22016)) + +> Anonymous says: +> +> Good work Steve + team! Looking forward to read more of this tutorial. Perhaps bring back some of the 3D transformations we used to since the LWUIT days? Also more ports for Windows and BB would be nice. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics.html) + + +### **Anonymous** — January 19, 2015 at 9:19 am ([permalink](https://www.codenameone.com/blog/codename-one-graphics.html#comment-21663)) + +> Anonymous says: +> +> Thanks Steve ! Good to know you are part of the cn1 team now, I always told the cn1 guys they are great but need more hands to do such a complex job. About the Shape API, I am eager to use it, but the absence of an Arc2D shape is a killer in many situations, I even wrote a nice whell-like progress component that was not accepted by Shai to be included because it relies on Graphics.drawArc, and the Bezier curves do not deliver an acceptable result in this case either. Also, I believe it should use floating point, it would deliver smoother Shapes, wouldn’t it ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics.html) + + +### **Anonymous** — January 19, 2015 at 1:07 pm ([permalink](https://www.codenameone.com/blog/codename-one-graphics.html#comment-22009)) + +> Anonymous says: +> +> I wasn’t involved during the LWUIT days. What 3D transformations are you referring to? We do support full 3D transformations in this pipeline via the Transform class. I’ll be going through that in a later tutorial. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics.html) + + +### **Anonymous** — January 19, 2015 at 1:13 pm ([permalink](https://www.codenameone.com/blog/codename-one-graphics.html#comment-24175)) + +> Anonymous says: +> +> I agree that drawArc() would be nice. You can implement it currently using a a series of lines or bezier curves, but this wouldn’t be as performant as an actual drawArc() primitive. Please file and issue on this. +> +> Changing to use floating point wouldn’t be terribly hard to do… It wouldn’t affect shapes drawn with GeneralPath (since that is already using floating point) but could potentially make things more flexible with aggregating multiple shapes and paths together. Please file an issue on this. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics.html) + + +### **Anonymous** — January 19, 2015 at 2:31 pm ([permalink](https://www.codenameone.com/blog/codename-one-graphics.html#comment-22100)) + +> Anonymous says: +> +> FYI the old Transition3D support: [https://www.youtube.com/wat…]() its around the second minute. Keep in mind this was all running on feature phones with 2mb of RAM. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics.html) + + +### **Anonymous** — January 30, 2015 at 6:51 pm ([permalink](https://www.codenameone.com/blog/codename-one-graphics.html#comment-22342)) + +> Anonymous says: +> +> For Steve Hannah: +> +> I’m teaching my grandsons Java by porting the Raspberry Pi Snake Game from Python to Java. Have it running in Java as an app, but they would really be pumped to get it on an iPad. Hence CN1. The core is some graphics and a game loop timer. Looking forward to your next post on animation. But having problems with your DrawingCanvas app post. +> +> I made a manual CN1 app in Eclipse. Added DisplayCanvas from your post. Used the straight line version of addPoint(). It turns out lastY is never used and lastX=x; is assigning a float to an int. Fixed the compile by: +> +> private int lastX=-1; +> +> // private int lastY=-1; +> +> public void addPoint(float x, float y){ +> +> if ( lastX == -1 ){ +> +> // this is the first point… don’t draw a line yet +> +> p.moveTo(x, y); +> +> } else { +> +> p.lineTo(x, y); +> +> } +> +> lastX = (int) x; +> +> // lastY = y; +> +> repaint(); +> +> } +> +> Inserted an addComponent(new DrawingCanvas()) right after adding the “Hello World” label component. +> +> Form hi = new Form(“Hi World”); +> +> hi.addComponent(new Label(“Hi World”)); +> +> hi.addComponent(new DrawingCanvas()); +> +> [hi.show](); +> +> Ran it. The simulator opened. It looked just the same as before inserting the addComponent(new DrawingCanvas()). I clicked a couple of points on the screen. Nothing happened. No breakpoint I put in DrawCanvass gets called. QUESTION: Should this work in the simulator? +> +> Switched from Drawing Canvas to something dead simple: +> +> public class DrawLine extends Component { +> +> public DrawLine() { +> +> super(); +> +> setSize(new Dimension(200, 200)); +> +> } +> +> public void paint(Graphics g) { +> +> g.drawLine(30, 30, 150, 150); +> +> } +> +> } +> +> Still nothing! HELP!!! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics.html) + + +### **Anonymous** — January 30, 2015 at 7:44 pm ([permalink](https://www.codenameone.com/blog/codename-one-graphics.html#comment-22327)) + +> Anonymous says: +> +> Thanks for pointing this out. There, in fact, were a couple of typos in the source. Check out the full sources here: +> +> [https://gist.github.com/sha…]() +> +> and here +> +> [https://gist.github.com/sha…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics.html) + + +### **Anonymous** — January 31, 2015 at 3:45 pm ([permalink](https://www.codenameone.com/blog/codename-one-graphics.html#comment-21840)) + +> Anonymous says: +> +> Still nothing comes up in the simulator but the “Hi World” label. And clicking on the screen below the label has no effect. Nothing with either your DrawingCanvas or DrawingCanvasBezier. And breakpoints put at the start of the 3 DrawingCanvas methods are never triggered — nothing in DrawingCanvas is getting called (other than its default constructor). +> +> public void start() { +> +> if(current != null){ +> +> [current.show](); +> +> return; +> +> } +> +> Form hi = new Form(“Hi World”); +> +> hi.addComponent(new Label(“Hi World”)); +> +> hi.addComponent(new DrawingCanvas()); +> +> [hi.show](); +> +> } +> +> And I updated the CN1 plugin into my Eclipse just a few days ago. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics.html) + + +### **Anonymous** — January 31, 2015 at 3:48 pm ([permalink](https://www.codenameone.com/blog/codename-one-graphics.html#comment-22200)) + +> Anonymous says: +> +> Strange. It works fine for me. Keep in mind, nothing should show up until your second click. The first click just marks the start of the line that will be produced by your second click. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics.html) + + +### **Anonymous** — January 31, 2015 at 4:23 pm ([permalink](https://www.codenameone.com/blog/codename-one-graphics.html#comment-21608)) + +> Anonymous says: +> +> Wait, I see the problem. You are using FlowLayout. The DrawingCanvas doesn’t have a preferred size set, it relies completely on the layout manager to size it. If you use a BorderLayout instead, then place the DrawingCanvas in the center, it will work. +> +> Steve +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics.html) + + +### **Anonymous** — January 31, 2015 at 6:16 pm ([permalink](https://www.codenameone.com/blog/codename-one-graphics.html#comment-21952)) + +> Anonymous says: +> +> That was it! Many thanks! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-graphics.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.md b/docs/website/content/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.md new file mode 100644 index 0000000000..3f69d2c6cd --- /dev/null +++ b/docs/website/content/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.md @@ -0,0 +1,169 @@ +--- +title: Codename One & Java Code Geeks are giving away free JavaOne Tickets (worth + $3,300)! +slug: codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300 +url: /blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300/ +original_url: https://www.codenameone.com/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html +aliases: +- /blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html +date: '2014-06-28' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300-1.jpg) + + + + + +![JavaOne 2014 exhibiting](/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300-1.jpg) + + + + +Would you like to go to +[ +JavaOne +](https://www.oracle.com/javaone/index.html) +? Besides being a cool conference its loads of fun with shows and events thru-out the city. + + + +Now you have a chance, +[ +Codename One +](http://www.codenameone.com/) +and +[ +Java Code Geeks +](http://www.javacodegeeks.com/) +have teamed up to give away TWO full passes (worth $1,650 each) and to win all you need to do is: + + + +– Retweet this tweet: +[ + +> [@Codename_One](https://twitter.com/Codename_One?ref_src=twsrc%5Etfw) & [@javacodegeeks](https://twitter.com/javacodegeeks?ref_src=twsrc%5Etfw) are giving away full [@JavaOneConf](https://twitter.com/JavaOneConf?ref_src=twsrc%5Etfw) passes (worth $1650 each) retweet and click to win — Java Code Geeks (@javacodegeeks) [June 30, 2014](https://twitter.com/javacodegeeks/status/483499905978490880?ref_src=twsrc%5Etfw) + + +](https://twitter.com/javacodegeeks/statuses/483499905978490880) + +and/or + +– Share this Facebook post: +[ + +> Codename One and Java Code Geeks are giving away free Java One passes worth $1,650 each! To win share this post and follow the instructions here: http://t.co/DPWni36AaU Posted by [Java Code Geeks](https://www.facebook.com/javacodegeeks/) on [Sunday, June 29, 2014](https://www.facebook.com/javacodegeeks/posts/690259861009205) ](https://www.facebook.com/javacodegeeks/posts/690259861009205) + + + +Finally fill out the form +[ +here +](https://docs.google.com/forms/d/1_VPxGyP1KRVBgPSlRndNWH0iGEiHKqnxPa3CPWl-rrs/viewform) +(notice only fill it once and don’t cheat or you will be disqualified!). + + + +We will hold a random draw based on the rules listed in the form then publish the results on July 15th 2014. Tickets will be handed out by the end of July. + + + +Good Luck! + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — July 9, 2014 at 7:17 am ([permalink](https://www.codenameone.com/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html#comment-21437)) + +> Anonymous says: +> +> Tweeted, Facebooked –> Tickets pleaaase 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html) + + +### **Anonymous** — July 9, 2014 at 11:37 am ([permalink](https://www.codenameone.com/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html#comment-21732)) + +> Anonymous says: +> +> If you submitted the form then its up to the guys at Java Code Geeks to raffle based on the rules highlighted in the contest form. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html) + + +### **Anonymous** — July 9, 2014 at 7:22 pm ([permalink](https://www.codenameone.com/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html#comment-22078)) + +> Anonymous says: +> +> Hi Shai, +> +> Will you be holding a stall anywhere else apart from the conference? I saw that the tickets are very expensive. I recently moved to SF and would like to meet the code name one team. Do let me know if you guys are holding stalls anywhere else. +> +> Thanks, +> +> Nikhil Dahake +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html) + + +### **Anonymous** — July 10, 2014 at 1:41 am ([permalink](https://www.codenameone.com/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html#comment-22186)) + +> Anonymous says: +> +> Hi, +> +> I don’t think there is an option to do that and we will practically be flying in/out right away so we won’t spend much time in the states. +> +> However, J1 has a discover pass that doesn’t allow much and should cost roughly $50. It allows you to see the pavilion booths and the big announcements/general sessions (if I remember correctly). I’m not sure if this is something you can buy via Oracles site, if not we might be able to provide you with access to such a pass. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html) + + +### **Anonymous** — July 10, 2014 at 2:36 pm ([permalink](https://www.codenameone.com/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html#comment-21934)) + +> Anonymous says: +> +> Hi Shai, +> +> Would the discover pass allow me to visit the CN 1 booth? The pass is retailing for $50 currently. +> +> Thanks, +> +> Nikhil +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html) + + +### **Anonymous** — July 11, 2014 at 1:35 am ([permalink](https://www.codenameone.com/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html#comment-21985)) + +> Anonymous says: +> +> I think so. I never had such a pass since I always had a speaker pass. You should check that it provides pavilion access which is where the booths should be. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html) + + +### **Anonymous** — July 11, 2014 at 9:21 pm ([permalink](https://www.codenameone.com/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html#comment-21970)) + +> Anonymous says: +> +> Yes, the disover pass allows you access to the exhibition hall and thats where the booth will be. I got myself a discover pass. Will visit your booth 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-live-updated-android-changes.md b/docs/website/content/blog/codename-one-live-updated-android-changes.md new file mode 100644 index 0000000000..95a09ad217 --- /dev/null +++ b/docs/website/content/blog/codename-one-live-updated-android-changes.md @@ -0,0 +1,85 @@ +--- +title: Codename One LIVE Updated & Android Changes +slug: codename-one-live-updated-android-changes +url: /blog/codename-one-live-updated-android-changes/ +original_url: https://www.codenameone.com/blog/codename-one-live-updated-android-changes.html +aliases: +- /blog/codename-one-live-updated-android-changes.html +date: '2013-12-15' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-live-updated-android-changes/codename-one-live-updated-android-changes-1.png) + + + + + +![Picture](/blog/codename-one-live-updated-android-changes/codename-one-live-updated-android-changes-1.png) + + + + +We finally got around to updating Codename One LIVE! and in the process also added a How Do I? video +[ +guiding you thru the process of using it +](/how-do-i---preview-my-designs-on-the-device-using-codename-one-live.html) +. + + +If you didn’t use Codename One LIVE! in the past its a really cool tool that allows you to instantly preview the design you build within the GUI builder right on the device. This works seamlessly for all devices although for iOS its difficult to get an app like that thru itunes and it requires a jailbroken device (unlike regular Codename One apps). + + + + + + + +This update also disables the feature for non-pro users, it was always listed as a pro user feature in our +[ +pricing page +](/pricing.html) +but in the past this wasn’t enforced. + +On a different subject, we made some major compatibility breaking changes to the Android port. Please test your application and see that it behaves correctly on start up, this is very important since we are about to release Codename one 2.0 and we want it to be very stable. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — December 16, 2013 at 7:37 pm ([permalink](https://www.codenameone.com/blog/codename-one-live-updated-android-changes.html#comment-22001)) + +> Anonymous says: +> +> When are you going to release ver 2.0? +> +> Any chance in the next 3 days 🙂 +> +> There is a Hackathon coming up here Thu/Fri and I would like to delve again into your framework but would prefer 2.0 if is already out. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-live-updated-android-changes.html) + + +### **Anonymous** — December 17, 2013 at 2:54 am ([permalink](https://www.codenameone.com/blog/codename-one-live-updated-android-changes.html#comment-21859)) + +> Anonymous says: +> +> It is scheduled for a bit later but what you have right now is functionally equivalent to 2.0. +> +> With a cloud service version releases have a very different meaning. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-live-updated-android-changes.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-maker-is-now-live-on-google-play.md b/docs/website/content/blog/codename-one-maker-is-now-live-on-google-play.md new file mode 100644 index 0000000000..4cbdb1060e --- /dev/null +++ b/docs/website/content/blog/codename-one-maker-is-now-live-on-google-play.md @@ -0,0 +1,70 @@ +--- +title: Codename One Maker Is Now Live On Google Play +slug: codename-one-maker-is-now-live-on-google-play +url: /blog/codename-one-maker-is-now-live-on-google-play/ +original_url: https://www.codenameone.com/blog/codename-one-maker-is-now-live-on-google-play.html +aliases: +- /blog/codename-one-maker-is-now-live-on-google-play.html +date: '2013-05-25' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-maker-is-now-live-on-google-play/codename-one-maker-is-now-live-on-google-play-1.png) + + + + +[ +![Picture](/blog/codename-one-maker-is-now-live-on-google-play/codename-one-maker-is-now-live-on-google-play-1.png) +](https://play.google.com/store/apps/details?id=com.codenameone.apps.maker) + + + +We just released an initial preview of +[ +Codename One Maker into Google Play +](https://play.google.com/store/apps/details?id=com.codenameone.apps.maker) +to start soliciting feedback on what we got wrong and what we need to improve. Let us know what you think and how we can improve it in the future. + + +We already intend to produce some of the following: + + + 1. +Drag and drop form builder – this won’t be a full fledged GUI builder (which requires real coding) but rather a simple way to create custom forms + + 2. +Plugins – will allow Codename One developers to create libraries that can be integrated into the built applications! + + 3. +Downloadable themes + + 4. +On device theme customization/creation + + 5. +Wizards to create more fleshed out applications from websites, blogs and social networks + +What do you think is most important, what do you think is missing? + + +As a side note we submitted the app to Apple and got rejected because we aren’t allowed to mention any other platforms on iOS (no blackberry or android mention). So the iOS users would only be able to build iOS apps (assuming we get approved)… Thanks Apple. + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-shared-files-library.md b/docs/website/content/blog/codename-one-shared-files-library.md new file mode 100644 index 0000000000..df75b4df31 --- /dev/null +++ b/docs/website/content/blog/codename-one-shared-files-library.md @@ -0,0 +1,153 @@ +--- +title: Codename One Shared Files Library +slug: codename-one-shared-files-library +url: /blog/codename-one-shared-files-library/ +original_url: https://www.codenameone.com/blog/codename-one-shared-files-library.html +aliases: +- /blog/codename-one-shared-files-library.html +date: '2023-07-26' +author: Steve Hannah +description: This library provides a wrapper over the Android shared files API to + allow your Codename One apps to read and write shared files (i.e. files accessible + to other apps). +--- + +This library provides a wrapper over the Android shared files API to allow your Codename One apps to read and write shared files (i.e. files accessible to other apps). + +![codename-one-shared-files-library](/blog/codename-one-shared-files-library/Shared-Files-Library-1024x536.jpg) + +> - See this on [GitHub.](https://github.com/shannah/cn1-shared-files-lib) +> +> - See example app using this API [here.](https://github.com/shannah/cn1-shared-files-lib-demo/tree/master/common/src/main/java/com/codename1/shfltest) +> +> - See use cases for accessing documents and other files [here.](https://developer.android.com/training/data-storage/shared/documents-files#use-cases) + +### Background + +#### Accessing documents and other files from shared storage (including external and cloud storage). + +In the past, we used to be able to access files on external storage directly using ****FileSystemStorage****, but more recent android versions block this, requiring you to use their[Shared Document APIs](https://developer.android.com/training/data-storage/shared/documents-files). a.k.a Share Files API and Storage Access Framework. + +On Android devices from version 4.4 and above, apps can use the ****Storage Access Framework**** to let users choose documents and files for the app without needing special permissions. This enhances user privacy and control, and the accessed files remain on the device even after uninstalling the app. + +The new Codename One Shared Files Library provides a wrapper over the Android shared files API to allow your Codename One apps to read and write shared files (i.e. files accessible to other apps). + +This is a clean, secure and well-supported way to save and open files that could also be accessed by other applications. + +### Basic Usage + +This API provides two abstractions: + +1. `SharedFile` – Represents a single file or directory. + +2. `SharedFileManager` – Provides access to the shared file system. Includes UI abstractions to select directories and files. + +First step is to request access to a file: + +```java + + // Open a directory +// Will open a file chooser for user to access a directory +SharedFileManager.getInstance().openDirectory().ready(sharedDirectory -> { + // sharedDirectory is a SharedFile object +}); + +// Open a file +SharedFileManager.getInstance().openFile().ready(sharedFile -> { + // sharedFile is a SharedFile object +}); + +// Open file of specific type +SharedFileManager.getInstance().openFile("text/plain").ready(sharedFile -> { + // sharedFile is a SharedFile object +}); + + +``` + +### Reading and Writing Files + +Use `SharedFile.openInputStream()` and `SharedFile.openOutputStream(String mimetype)` for reading and writing files. + +E.g. + +```java + + String textContents = Util.readToString(sharedFile.openInputStream()); + +textContents += "Modified"; +try (OutputStream output = sharedFile.openOutputStream(sharedFile.getMimetype())) { + output.write(textContents.getBytes("UTF-8")); +} + + +``` + +### Creating New Files + +1. Open a directory + +2. Call `directory.getChild(relativePath)` to get reference to file. + +3. Call `child.openOutputStream(mimetype)` + +### Bookmarking For Later Use + +By default, the files you obtain will no be accessible the next time you load the app. You need to create a bookmarked file which will provide you with a persistent path that you can use to access the file. + +1. Use `SharedFile.createBookmark()` to create a bookmark. + +2. Use `SharedFile.deleteBookmark()` do remove a bookmark. + +3. Use `SharedFile.isBookmark()` to check if the file is a bookmarked file. + +4. Use `SharedFileManager.openBookmark(String)` to open a file given its bookmarked path. (i.e. bookmarkedFile.getPath()) + +5. Use `SharedFileManager.getBookmarks()` for a list of all current bookmarks. + +### Installation + +Add the following maven dependency to your common/pom.xml file + +```xml + + + com.codenameone + sharedfiles-lib + 0.1.0 + pom + + + +``` +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved here for historical context. New discussion happens in the Discussion section below._ + + +### **Wits ICT** — August 1, 2023 at 10:26 pm ([permalink](https://www.codenameone.com/blog/codename-one-shared-files-library.html#comment-24565)) + +> Wits ICT says: +> +> Thanks for this. And good to see blogs returning after a while. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-shared-files-library.html) + + +### **Mobi Tribe** — October 10, 2023 at 12:49 pm ([permalink](https://www.codenameone.com/blog/codename-one-shared-files-library.html#comment-24580)) + +> Mobi Tribe says: +> +> Thanks @Steve Hannah. This is awesome. Very useful… As @Wits ICT has said, glad to see you guys back. Hopefully you, Chen and Shai and the rest of the cn1 family still have good stuff in store. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-shared-files-library.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-simulator-facelift.md b/docs/website/content/blog/codename-one-simulator-facelift.md new file mode 100644 index 0000000000..00c810ccd2 --- /dev/null +++ b/docs/website/content/blog/codename-one-simulator-facelift.md @@ -0,0 +1,190 @@ +--- +title: Codename One Simulator Facelift +slug: codename-one-simulator-facelift +url: /blog/codename-one-simulator-facelift/ +original_url: https://www.codenameone.com/blog/codename-one-simulator-facelift.html +aliases: +- /blog/codename-one-simulator-facelift.html +date: '2022-03-18' +author: Steve Hannah +description: With the latest Maven update (7.0.61), you will notice a few changes + to the Codename One simulator that should improve your development experience. +--- + +With the latest Maven update (7.0.61), you will notice a few changes to the Codename One simulator that should improve your development experience. + +![Simulator Facelift - Codename One](/blog/codename-one-simulator-facelift/Simulator-Facelift-Codename-One-1024x536.jpg) + +We have consolidated the user interface inside a single window so that the component inspector, network monitor, and other tools feel more integrated. + +The window has four regions (Left, Center, Right, and Bottom), and you are free to place any of the UI panels into any of these regions. The default configuration places the simulator in the center, the component tree on the left, and the component details and network monitor in the bottom, but you can change this using the `"Move To"` menu, and it will remember your preferences the next time you run the simulator. + +![](/blog/codename-one-simulator-facelift/default-configuration.png) + +Figure 1. The default simulator window configuration, with component tree on the left, the simulator in the center, and the component details on the bottom. + +For example, if you wanted the component tree to appear in the **“right”** region, you could click on the panel menu in the upper right of the `Components` panel. + +![](/blog/codename-one-simulator-facelift/move-to-right.png) + +And the resulting configuration would look like the following: + +![](/blog/codename-one-simulator-facelift/comonents-on-right.png) + +If you prefer to break out a panel into a separate window, you can do that also. When you close the window, it will automatically be returned to its original region inside the main simulator window. + +For example, if we wanted to move the simulator itself to a separate window, we could select the panel menu in the uper right of the **Simulator** panel, and select `"Move To" > "New Window"` + +![](/blog/codename-one-simulator-facelift/move-to-separate-window.png) + +The result would be the simulator in its own window as shown below: + +![](/blog/codename-one-simulator-facelift/simulator-in-separate-window.png) + +Your configuration will be remembered for your next run, so you wan’t have to repeat yourself. + +### Menu Changes + +As part of this change, we have moved some of the items from the **Simulator** menu onto a new toolbar in the **Simulator** panel. For example instead of a `"Simulator" > "Rotate"` menu item, there are toggle buttons on the toolbar for `"Portrait" and "Landscape".` And instead of `"Simulator" > "Zoom",` there are `Zoom In` and `Zoom Out` buttons on the toolbar. + +![](/blog/codename-one-simulator-facelift/simulator-toolbar.png) + +### More to come…​ + +Over the next few updates we will be doing some more reorganization of menu items and panels to make the experience more cohesive. We will also be adding a few new features to enhance the dev experience. Stay tuned…​ +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved here for historical context. New discussion happens in the Discussion section below._ + + +### **Diamond Mubaarak** — March 22, 2022 at 6:22 am ([permalink](https://www.codenameone.com/blog/codename-one-simulator-facelift.html#comment-24514)) + +> Diamond Mubaarak says: +> +> Consolidating the simulating tools is excellent. I know this is a work in progress but some functionalities are off or could be improved. +> +> – Network monitor has no records. +> – Components are not selectable on UI with MapContainer. The tree could be expanded, though. Only the root form is selectable. +> – Selection of a component in the Components pane should switch to the Component Details tab automatically. +> – Rotating a device should automatically increase and decrease in size the Simulator pane to show the whole device. +> – “Always on Top” functionality should apply to secondary windows like “Push Simulation” or when I set the Simulator pane to show as a new window, as these windows are hidden behind the main window until it’s unchecked. +> – The “Move To” overflow menu appears behind the Simulator until you hover on it. +> – Zooming in or out is great, however, zoom in should come with the ability to pan the screen. +> +> I’m running the new Simulator on a Linux OS. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-simulator-facelift.html) + + +### **Steve Hannah** — March 22, 2022 at 6:59 pm ([permalink](https://www.codenameone.com/blog/codename-one-simulator-facelift.html#comment-24515)) + +> Steve Hannah says: +> +> Thanks for the feedback. I have moved this into an issue and am working through the points one by one. You can follow the progress at +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-simulator-facelift.html) + + +### **Steve Hannah** — March 28, 2022 at 1:46 pm ([permalink](https://www.codenameone.com/blog/codename-one-simulator-facelift.html#comment-24524)) + +> Steve Hannah says: +> +> All of these issues are resolved in the latest version (7.0.62). You can follow the specific changes in the issue tracker issue that I opened for this at +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-simulator-facelift.html) + + +### **plumberg** — March 28, 2022 at 8:23 pm ([permalink](https://www.codenameone.com/blog/codename-one-simulator-facelift.html#comment-24525)) + +> plumberg says: +> +> Hi, +> +> I tried opening Network Monitor after last update (just updated cn1 few min ago), but Network monitor window is not opening. Nothing is happening +> +> I’ll appreciate your help! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-simulator-facelift.html) + + +### **plumberg** — March 28, 2022 at 8:27 pm ([permalink](https://www.codenameone.com/blog/codename-one-simulator-facelift.html#comment-24526)) + +> plumberg says: +> +> Nevermind, I just found it in the same window on the bottom. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-simulator-facelift.html) + + +### **Steve Hannah** — March 28, 2022 at 11:06 pm ([permalink](https://www.codenameone.com/blog/codename-one-simulator-facelift.html#comment-24527)) + +> Steve Hannah says: +> +> Thanks for sharing that you had trouble find it. I’ll see what I can do to make this more intuitive. + + +### **Abdelaziz Makhlouf** — March 25, 2022 at 1:00 pm ([permalink](https://www.codenameone.com/blog/codename-one-simulator-facelift.html#comment-24516)) + +> Abdelaziz Makhlouf says: +> +> Hello, +> Due to this update, all components are very small now : +> How to fix this please or how to get back to the older version ? We can’t even read the text. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-simulator-facelift.html) + + +### **Steve Hannah** — March 25, 2022 at 2:16 pm ([permalink](https://www.codenameone.com/blog/codename-one-simulator-facelift.html#comment-24517)) + +> Steve Hannah says: +> +> The changes to the simulator shouldn’t have any effect on component sizes in your app. One way to confirm this is to revert the version to 7.0.58. If you change the cn1.version property to 7.0.58 in your project’s pom.xml file, does that “fix” the issue? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-simulator-facelift.html) + + +### **Fawaz Qamhawi** — March 26, 2022 at 8:39 pm ([permalink](https://www.codenameone.com/blog/codename-one-simulator-facelift.html#comment-24518)) + +> Fawaz Qamhawi says: +> +> This is happening with me. +> If I will need to save the css file again after each run, it will compile again. That will fix the problem. +> +> By the way, I lost all my skins and there is no way to upload other skins as it used to be before this update. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-simulator-facelift.html) + + +### **Steve Hannah** — March 27, 2022 at 12:37 pm ([permalink](https://www.codenameone.com/blog/codename-one-simulator-facelift.html#comment-24519)) + +> Steve Hannah says: +> +> > By the way, I lost all my skins and there is no way to upload other skins as it used to be before this update. +> +> You can still add skins in exactly the same way that you added skins before. “Skins” > “More”. or “Skins” > “Add New”. This functionality is unchanged. +> +> > If I will need to save the css file again after each run, it will compile again. That will fix the problem. +> +> I’m not sure I understand the issue? Are you saying that your problem with styles is fixed after you recompile the CSS file? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-simulator-facelift.html) + + +### **Steve Hannah** — March 28, 2022 at 1:44 pm ([permalink](https://www.codenameone.com/blog/codename-one-simulator-facelift.html#comment-24523)) + +> Steve Hannah says: +> +> I have opened an issue in the issue tracker at +> If you experience this issue, please update that issue with details to help reproduce it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcodename-one-simulator-facelift.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/codename-one-store.md b/docs/website/content/blog/codename-one-store.md new file mode 100644 index 0000000000..45ba56ef82 --- /dev/null +++ b/docs/website/content/blog/codename-one-store.md @@ -0,0 +1,38 @@ +--- +title: Codename One Store +slug: codename-one-store +url: /blog/codename-one-store/ +original_url: https://www.codenameone.com/blog/codename-one-store.html +aliases: +- /blog/codename-one-store.html +date: '2016-06-13' +author: Shai Almog +--- + +![Header Image](/blog/codename-one-store/generic-java-1.jpg) + +Are you interested in selling your custom made themes, templates & libraries for Codename One? + +[Eric Dodji Gbofu](http://twitter.com/doderic/) founder of [Codename One Fr](http://www.codenameonefr.com/) and author of the French language +[Codename One book](https://www.codenameone.com/blog/book-continued-migration.html) is launching +a [Codename One store](http://www.codenameone-store.com/). + +This is meant as a Codename One equivalent to sites such as theme forest that provide ready made templates +of various kinds for a reasonable price. It answers a very common need within the community to get started +with a cookie cutter solution. + +The site has been under development for a while and is now collecting submissions of themes, templates, libraries +etc. + +If you have questions about the site there is also an email contact there as well. + +We are quite pleased with the community picking up such things, but keep in mind that the site isn’t directly +affiliated with us so we can’t answer questions or provide help/advice in that regard. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/combining-salesforce-and-codename-one.md b/docs/website/content/blog/combining-salesforce-and-codename-one.md new file mode 100644 index 0000000000..738c44499b --- /dev/null +++ b/docs/website/content/blog/combining-salesforce-and-codename-one.md @@ -0,0 +1,93 @@ +--- +title: Combining SalesForce and Codename One +slug: combining-salesforce-and-codename-one +url: /blog/combining-salesforce-and-codename-one/ +original_url: https://www.codenameone.com/blog/combining-salesforce-and-codename-one.html +aliases: +- /blog/combining-salesforce-and-codename-one.html +date: '2013-03-25' +author: Shai Almog +--- + +![Header Image](/blog/combining-salesforce-and-codename-one/combining-salesforce-and-codename-one-1.jpg) + +This is a guest post by Bertrand Cirot, based on an original blog post that appeared +[ +here +](http://www.tuto-codenameone.ch/salesforce-et-codename-one/) +. Bertrand works as an SFDC, Flex and Java/J2EE developer in Switzerland. Closely interested in mobile device solutions, he writes on +[ +Tuto-CodenameOne.ch +](http://www.tuto-codenameone.ch/) +which proposes tutorials for the French-speaking community. + +* * * + +While investigating the possibilities within Codename One, I made a discovery that I would like to share with you via this short article. But first lets discuss SalesForce, it is a CRM platform. Which has an advantage of an open Web Service API enabling it for use with Codename One. + +** +This is an ideal combination that provides simple and effective customer management on all mobile devices. +** + +## SalesForce, a complete platform + + + + +[ +![Picture](/blog/combining-salesforce-and-codename-one/combining-salesforce-and-codename-one-1.jpg) +](http://www.salesforce.com/) + +SalesForce is a CRM (Customer Relationship Management) platform that is fully hosted in the cloud, as indicated by it’s logo. SalesForce (SFDC) is a leader in sales management tools, it provides a complete and evolutionary system. Many tools are available and configurable in a simple and efficient way to manage all the essential information about the sales activity. In addition, the platform is fully integrated with communication tools, social networking and instant messaging. + +* * * + +[ +![Picture](/blog/combining-salesforce-and-codename-one/combining-salesforce-and-codename-one-2.png) +](/img/blog/old_posts/combining-salesforce-and-codename-one-large-4.png) + +Once You connect the SalesForce interface, you can easily add standard data: Users, Accounts, Products, Contacts, etc. Everything is added via forms based interface, If you wish, you can also add new fields to the Available Objects or create new ones from scratch. + +SalesForce can therefore easily form a set of custom data hosted in the Cloud. More importantly for mobile development, the SFDC platform offers several communication API’s allowing third party applications access to its data (SOAP, Bulk or REST). + +Personally recommend the REST architecture mainly for bandwidth reasons, even though it is more restrictive in terms of implementation and use. + +## SalesForce One and Codename: a winning combination + +[ +![Picture](/blog/combining-salesforce-and-codename-one/combining-salesforce-and-codename-one-3.png) +](http://wiki.developerforce.com/page/REST_API) + +In order to make ​​a Codename One application communicate with SalesForce, I performed some tests. + +My starting point was the official documentation of the REST API: I soon managed to authenticate and execute a query to retrieve a list of distant objects. + +## What’s next? + +Still, I could not stop there so I decided to use the opportunity to try the new library support that was recently introduced to Codename One and create a SalesForce library. There is still a lot of work to be done, there are bugs and only a small part of the API is exposed in the library. I will try to tackle these issues one at a time and I will keep you informed of my progress. If you are interested, the code is available on Google Code under the name: +[ +CodenameOne-SFDC-Lib +](https://code.google.com/p/codenameone-sfdc-lib/) +. + +** +If you want to help me in pushing forward the development of the library faster, do not hesitate to contact me, I’d love to have some help +** +. + +Bertrand CIROT + +writer on +[ +Tuto-CodenameOne +](http://www.tuto-codenameone.ch/) + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/compare-thru-property-cross.md b/docs/website/content/blog/compare-thru-property-cross.md new file mode 100644 index 0000000000..bc8dbfd62f --- /dev/null +++ b/docs/website/content/blog/compare-thru-property-cross.md @@ -0,0 +1,78 @@ +--- +title: Compare Thru Property Cross +slug: compare-thru-property-cross +url: /blog/compare-thru-property-cross/ +original_url: https://www.codenameone.com/blog/compare-thru-property-cross.html +aliases: +- /blog/compare-thru-property-cross.html +date: '2016-07-03' +author: Shai Almog +--- + +![Header Image](/blog/compare-thru-property-cross/property-cross-new.jpg) + +We just updated the [QT](/blog/comparing-qt-and-codename-one.html) and +[Xamarin](/blog/comparing-xamarin-and-codename-one.html) comparisons to Codename One that we did a while back. +Those comparisons now include a [property cross](/blog/property-cross-revisited.html) comparison section. +Property Cross is really valuable for comparing the differences between various cross platform development +solutions and Codename One has the smallest implementation (in terms of lines of code) by far! + +Our implementation is also quite superior in some other ways providing features such as infinite scrolling instead +of simple paging etc. + +We think that just by looking at the Codename One project and comparing it to the equivalent cross platform +tools Codename One’s advantages become pretty clear. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — July 6, 2016 at 3:12 pm ([permalink](https://www.codenameone.com/blog/compare-thru-property-cross.html#comment-21631)) + +> Chidiebere Okwudire says: +> +> My two cents: I personally think LOC comparisons are marginally important and somewhat misleading. The user does not see how many LOCs an app has but does see the UI and experience good or bad performance. I think such CPT comparisons should focus more on user experience and development costs (which includes the costs of the development tools, licenses, etc.) instead of on stuff that probably make developers somewhat happier but do not contribute that much to the end goal of apps that are attractive, robust and performant. +> +> By the way, the CN1 implementation is still missing from the property cross website – a lost (but redeemable) opportunity for some free PR if you ask me! Maybe time to give it another shot? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcompare-thru-property-cross.html) + + +### **Shai Almog** — July 6, 2016 at 5:38 pm ([permalink](https://www.codenameone.com/blog/compare-thru-property-cross.html#comment-22828)) + +> Shai Almog says: +> +> All of those are good points. As I mentioned LoC isn’t a great measure but when it’s 3x or higher for most other solutions it does indicate something. Personally I think our solution is also the most readable but I have such a heavy cognitive bias I can’t really evaluate these things. +> Performance and usability of the end result application is something I can’t objectively discuss as a fact. So I’d rather leave it to the developers to read thru the code and see if this makes sense then try to compile each of the solutions. +> +> Development costs are really hard to evaluate, costs for licenses etc. are things that shift and with the exception of QT all the solutions we evaluated are free/open source. +> +> I did try again recently, tried contacting the guy who did the last commit to their repo etc. both thru twitter, his email account etc. There is an issue HE opened asking for a Codename One version. I submitted a pull request and commented a few times… Nothing. +> This is quite frustrating. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcompare-thru-property-cross.html) + + +### **Chidiebere Okwudire** — July 8, 2016 at 8:09 am ([permalink](https://www.codenameone.com/blog/compare-thru-property-cross.html#comment-22545)) + +> Chidiebere Okwudire says: +> +> Thanks for your response. It surprises me that there are not much objective comparisons in the dimensions that arguably matter most, some of which I’ve mentioned above (user experience, performance, costs). I know it’s not easy but it’s definitely possible albeit in a somewhat “academic” fashion. +> +> PropertyCross is one of the best initiatives I’ve found in this regard though it only scratches the surface and as you’ve mentioned, the maintainers are not as responsive as one would like. Apparently, they find it more important to change the layout of their homepage instead of incorporating the CN1 comparison (and other pending pull requests?)! +> +> Talking about costs, while it’s hard to evaluate, it’s worth mentioning some facts. For instance, in one of your previous comparisons (with Xamarin if I’m not mistaken), you highlighted that CN1 support a web app version. That’s definitely a killer feature but what is glaringly missing is a mention of the fact that it is an enterprise-only feature (read $399 per month). Now, that fact makes a H-U-G-E difference in the cost-benefit equation. +> +> As you rightly mentioned, most of the solutions are open-source at the core but often have paid extras which make a huge difference. It must be possible to compare these quite objectively – free against free, paid against paid (grouped by feature set not subscription model), etc. I’m not saying you have to do that; all I’m trying to point out is that while you’re obviously positively biased towards CN1, it’s still possible to do more rigorous comparisons 😉 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcompare-thru-property-cross.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/comparing-phonegap-cordova-and-codename-one.md b/docs/website/content/blog/comparing-phonegap-cordova-and-codename-one.md new file mode 100644 index 0000000000..be15086757 --- /dev/null +++ b/docs/website/content/blog/comparing-phonegap-cordova-and-codename-one.md @@ -0,0 +1,273 @@ +--- +title: Comparing PhoneGap/Cordova and Codename One +slug: comparing-phonegap-cordova-and-codename-one +url: /blog/comparing-phonegap-cordova-and-codename-one/ +original_url: https://www.codenameone.com/blog/comparing-phonegap-cordova-and-codename-one.html +aliases: +- /blog/comparing-phonegap-cordova-and-codename-one.html +date: '2016-06-27' +author: Shai Almog +--- + +![Header Image](/blog/comparing-phonegap-cordova-and-codename-one/compare-to-cordova.jpg) + +Last time around we compared [Codename One to Xamarin](/blog/comparing-xamarin-and-codename-one.html) and this +time around I’d like to compare [Codename One](/) to what is probably the market leader: PhoneGap/Cordova. If Xamain +is big then Cordova is huge, it is so prevalent that it is often the default assumption when people mention cross +platform today. + +In fact, one of the big problems we had when describing Codename One was distinguishing it from HTML5 based +solutions like Cordova. + +One of the things we’d like to clarify before delving into the comparison is that our goal isn’t to proclaim Codename One +as the “end all” of WORA…​ +We are biased so the comparison might be flawed. However, we think Cordova/PhoneGap are remarkably +innovative tools that changed the marketplace significantly. The goal of this comparison is to highlight the +differences/tradeoffs of each solution. In fact we rather like Cordova and even offer some +[Cordova compatibility](/blog/phonegap-cordova-compatibility-for-codename-one.html) in Codename One…​ + +We were debating a lot on whether we should include Ionic in this comparison and decided to mostly skip it for now. +We mention it and related frameworks in the comparison in a few points mostly because PhoneGap is usually used +with such frameworks. Unfortunately because of the number of JavaScript frameworks and tools built on top +of PhoneGap it’s just impractical to single out each and every one of them. + +We might do a proper discussion of Ionic as I think it’s a very interesting solution that is very similar to Codename One +in some regards. Most of the things we discuss about PhoneGap/Cordova apply to ionic too. + +### Background + +PhoneGap was started in the iPhoneDevCamp hackathon, this highlights the genius behind the solution: +the underlying idea is trivial. PhoneGap is in-effect a **very** simple solution which is a pretty good thing. + +PhoneGap places a single web view UI within an app which it then uses to display HTML. It exposes a set of +JavaScript API’s to provide access to native functionality e.g. camera, filesystem etc. + +It also includes a rich set of plugins that provide quite a few capabilities, in fact we just ported one of those +great plugins to add [bluetooth support to Codename One](/blog/bluetooth-support.html)…​ + +Adobe purchased Nitobi who made PhoneGap and open sourced the project thru Apache as the Cordova project. +Both PhoneGap and Cordova are very similar with PhoneGap offering some pretty interesting features on top of +the core open source product such as PhoneGap build. + +Because Cordova/PhoneGap is so simple it was adopted throughout the industry practically all major enterprise mobility +tools such as Worklight rely on it for their client side UI. It’s become a synonym for the idea of packaging HTML +as an application and even tools that are not using Cordova internally are often referred to as PhoneGap or Cordova. + +In fact even we announced [PhoneGap/Cordova support](/blog/phonegap-cordova-compatibility-for-codename-one.html) +a while back and it didn’t take much to implement that…​ + +### At a Glance + +Category | PhoneGap/Cordova | Codename One +---|---|--- +Language | HTML, CSS & JavaScript | Java +Packaging | Packaged code optionally obfuscated | Compiled binaries +VM Ownership | Device/OS vendor | Codename One +Cloud Build | Yes thru PhoneGap build | Yes +Web Deployment | Yes | Yes +Widgets | HTML/Lightweight | Lightweight +Size Overhead | Depends on framework | Small + +### In Detail + +#### Language + +We’ve always said that if you love doing client side HTML/JavaScript for mobile devices then PhoneGap/Cordova +is probably the right tool for you. HTML5 has come a very long way and is no longer as restrictive as it used to be +especially with recent iOS updates. + +However, Java is still a formidable opponent. Unlike HTML/JavaScript, Java is strict, statically typed and compiled. + +JavaScript isn’t the most intuitive language to interface into native code. Native concepts such as threads or even +binary data don’t map in a natural way to the higher level functions of JavaScript. This isn’t the case for Java which +is literally the native language of Android and maps rather well to C/Objective-C/Swift concepts. + +With modern Java 8 semantics Java is also quite terse and should be comparably elegant to JavaScript in most +regards. + +#### Packaging + +PhoneGap applications are just zipped into the standard OS distribution. A complaint some PhoneGap developers +have is that hackers in some markets unzip their apps and take the HTML/JavaScript/CSS etc. into their own +app. This allows them to sell the app within the standard markets as if it was their own. Such scams are +quite common and very hard to catch/enforce. + +This is not feasible in Codename One where the source code is compiled together and obfuscated by default +on Android making it even more “secure”. A Codename One application can be decompiled but this would be +a far harder process than doing the same for a PhoneGap/Cordova application. + +#### VM Ownership + +Java is the native platform for Android whereas JavaScript/HTML are supported everywhere by the OS vendor. + +This brings about some interesting situations, Android completely replaced it’s browser implementation between +versions of the OS relatively abruptly. This can trigger a situation where shipping applications will start misbehaving +due to OS changes. This also means that the only way to fix some issues is thru a workaround, there is no central +authority that can fix an HTML rendering issue or add a missing feature to an old OS. + +With Codename One the VM and UI are the responsibility of a single entity. Since the implementation of Codename One +is at a lower point in the porting stack most of the relevant code can be ported/fixed or worked around by Codename One +itself. This means that if a low level reproducible failure happens, Codename One has the ability to fix it whereas +PhoneGap developers would need to workaround it. + +#### Cloud Build + +PhoneGap Build supports building native applications via the cloud which is a wonderful approach. +Codename One works in the same way but unlike PhoneGap build, Codename One is built around that +approach as a basic expectation. + +PhoneGap build works with a set of pre-determined plugins whereas Codename One is more flexible with +it’s support for native code and 3rd party libraries. + +#### Widgets + +Codename One uses lightweight widgets to do it’s rendering. Arguably HTML can be considered lightweight +as well but it is often not the case. + +One of the core powers of HTML has been it’s complex support for dynamic reflows, this allows positioning +components using a very elaborate box model. However, this power is also the source of HTML’s greatest performance +challenges. Some HTML frameworks choose to position elements absolutely and lay them out thru code +logic, which is pretty close to what Codename One does in it’s layout managers. However, this forces the +JavaScript developer into a custom environment that won’t “play nicely” with everything else within the ecosystem. + +Frameworks like Ionic have taken up the lightweight approach to creating native “themes” in a similar way to +Codename One. This provides Ionic with many of the advantages Codename One enjoys but also some of the +drawbacks/advantages inherent from layering on top of Cordova. + +One of the core capabilities of Codename One is in embedding native widgets directly into the app. This is demonstrated +in Codename One thru the native Google Maps support and other such capabilities. Since embedding an OS +native widget into HTML is “problematic” that level of platform extension can’t be accomplished in Cordova. + +#### Size Overhead + +Cordova and Codename One can be used to create very small applications. In fact Cordova can be even smaller +than Codename One in the hands of a skilled developer. + +However, using Cordova without a JavaScript framework/tooling is more challenging and less common today. +These tools include their own overhead which is rather extensive in some cases. E.g. Ionic is specifically well +known for producing very large application binaries. + +### Property Cross Comparison + +The PropertyCross demo was built as a tool that allows us to compare two cross platform frameworks, as such +there are versions of the demo for many such platforms. You can check out details of the Codename One +implementation [here](/blog/property-cross-revisited.html). The github repository for this demo +is [here](https://github.com/codenameone/PropertyCross/). + +Since PhoneGap/Cordova is mostly an infrastructure tool there are several implementations that support PhoneGap +Build. E.g. [jquerymobile](https://github.com/tastejs/PropertyCross/tree/master/jquerymobile), +[ionic](https://github.com/tastejs/PropertyCross/tree/master/ionic), +[sencha touch](https://github.com/tastejs/PropertyCross/tree/master/senchatouch2) and too many others to even +count…​ + +With so many variations how can we properly compare the two frameworks? + +There are several things we can gleam from property cross by reviewing all of the above: + + * Codename One has 2 file types that aren’t configuration or build scripts: res file (resources) & Java files. +PhoneGap solutions use JavaScript, HTML & CSS. + + * Codename One doesn’t have splashscreens or multiple icon sizes…​ Those are generated automatically unlike +the PhoneGap based solutions where you need dozens of resource files even without tablet support! + + * Codename One is terse. Ionic, is one of the smallest implementations. It includes more than 600 lines of +undocumented code spread across JavaScript and HTML (not counting angular, other JS libraries or CSS). +The Codename One implementation has 623 lines of code out of which over 150 lines are comments and 40 +lines are import statements…​ +**Who says Java is verbose?** + +### Final Word + +Notice that Codename One can +[embed PhoneGap/Cordova code](/blog/phonegap-cordova-compatibility-for-codename-one.html) into +Codename One applications. Would that make it superior to just using Cordova directly? + +Not necessarily. Cordova is a mature, widely supported solution. If you like working with HTML/JavaScript +then it’s hard to compete with that…​ + +However, if you want to use proper Java to develop your app and care more about the security of your code +then Codename One has advantages. + +If you think we misrepresented Codename One or PhoneGap/Cordova in any way let us know in the comments. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — June 28, 2016 at 8:46 pm ([permalink](https://www.codenameone.com/blog/comparing-phonegap-cordova-and-codename-one.html#comment-21514)) + +> bryan says: +> +> CN1 vs React Native ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-phonegap-cordova-and-codename-one.html) + + +### **Shai Almog** — June 29, 2016 at 4:19 am ([permalink](https://www.codenameone.com/blog/comparing-phonegap-cordova-and-codename-one.html#comment-22451)) + +> Shai Almog says: +> +> Agreed. I already wrote something but it wasn’t a real comparison: [http://www.codenameone.com/…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-phonegap-cordova-and-codename-one.html) + + +### **bryan** — June 29, 2016 at 4:34 am ([permalink](https://www.codenameone.com/blog/comparing-phonegap-cordova-and-codename-one.html#comment-22920)) + +> bryan says: +> +> ah.. yes I remember now. Would be good to get a feature for feature comparison. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-phonegap-cordova-and-codename-one.html) + + +### **José Ignacio Santa Cruz** — June 29, 2016 at 12:39 pm ([permalink](https://www.codenameone.com/blog/comparing-phonegap-cordova-and-codename-one.html#comment-22950)) + +> José Ignacio Santa Cruz says: +> +> Seems you haven’t seen [http://microsoft.github.io/…]() yet. +> Nice comparison, I used CN1 in the early LWUIT days. Due to the lack of Android support those days I went native and finally hybrid using jQuery mobile. Today I’m using Ionic, but the main reason is because of how fast can my team deliver an almost ready product, making HTML is fast and easy. JavaScript developers are not so difficult to find, and if you have design issues, giving the CSS to a designer is no big deal, he/she won’t have to learn anything new. It needs tweaking and tooling and putting brain on the deployment process to get small sized and small memory footprint apps, just like any other developing strategy chosen. +> Not better or worse, just different, aimed for different needs. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-phonegap-cordova-and-codename-one.html) + + +### **Shai Almog** — June 29, 2016 at 1:20 pm ([permalink](https://www.codenameone.com/blog/comparing-phonegap-cordova-and-codename-one.html#comment-22927)) + +> Shai Almog says: +> +> Thanks for the headsup, I actually did see this when it was announced and it totally slipped my mind. I wonder how well it works with the native HTML rendering? +> +> Codename One is totally different from LWUIT by now, we even have some CSS support. Although the “giving CSS to a designer” line is a bit… I’ve worked a lot with designers and never got anything remotely close to a usable CSS snippet from them. The best they could offer is the CSS photoshop produces for a layer which isn’t much… +> +> In mobile where the design needs to be aware of screen size, density, orientation, font constraints etc. the design requires proper programming skills. I’ve yet to see a designer produce something half decent for a website and I can’t imagine one producing something workable for cross platform mobile devices… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-phonegap-cordova-and-codename-one.html) + + +### **David Hinckley** — July 1, 2016 at 11:15 am ([permalink](https://www.codenameone.com/blog/comparing-phonegap-cordova-and-codename-one.html#comment-22784)) + +> David Hinckley says: +> +> I am a Java/Android developer and was asked to create an Android watch application to be added to an existing Cordova project. I was hoping that Cordova could receive requests from the watch through Android Wear messaging, but our Cordova expert says that Cordova can only receive Wear messages, if the Cordova app is currently in the foreground. It appears Cordova can’t run in the background without writing native code. If this is true, it may be important when considering Cordova. So, I ended up writing the native Android Wear message receiving piece for Cordova. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-phonegap-cordova-and-codename-one.html) + + +### **amikeliunas** — July 6, 2016 at 4:58 am ([permalink](https://www.codenameone.com/blog/comparing-phonegap-cordova-and-codename-one.html#comment-22410)) + +> amikeliunas says: +> +> Was that a comment, concern, or just venting out? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-phonegap-cordova-and-codename-one.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/comparing-qt-and-codename-one.md b/docs/website/content/blog/comparing-qt-and-codename-one.md new file mode 100644 index 0000000000..c1b22a433c --- /dev/null +++ b/docs/website/content/blog/comparing-qt-and-codename-one.md @@ -0,0 +1,524 @@ +--- +title: Comparing QT and Codename One +slug: comparing-qt-and-codename-one +url: /blog/comparing-qt-and-codename-one/ +original_url: https://www.codenameone.com/blog/comparing-qt-and-codename-one.html +aliases: +- /blog/comparing-qt-and-codename-one.html +date: '2016-04-27' +author: Shai Almog +--- + +![Header Image](/blog/comparing-qt-and-codename-one/compare-to-qt.jpg) + +We get a lot of requests to compare Codename One to other technologies and while we do have a comparison +page it is somewhat static. Doing a comparison within a blog post does have the advantage of focusing on +one technology and allowing comments. In this segment we’ll compare the venerable QT to Codename One. + +When developers started asking for this comparison I was of the opinion that it made no sense. The technologies +are so far apart from one another that they defy any sensible comparison. I still think the conceptual difference is +a bit too great but I’ll try to bridge some of the gap. + +__ | We updated this comparison after the initial publication to include the additional Property Cross section +---|--- + +__ | We updated this again to reflect pricing, terms & lightweight/heavyweight mixing +---|--- + +### Background + +QT went thru a lot over it’s many years. It’s the basis of the excellent KDE Linux desktop environment which in +my humble opinion was always superior to gnome. It’s a C++ library & toolchain developed by a company called +Trolltech that was purchased by Nokia. + +Nokia purchased Trolltech with the goal of taking QT into mobile, this went thru many iterations over the years +but the product that’s available today is radically different to everything available since. + +### At a Glance + +Table 1. QT vs. Codename One Category | QT | Codename One +---|---|--- +Language | C++/QML-JavaScript | Java +Cloud Build | No (requires Mac & Windows for full OS support) | Yes (can work on Linux for iOS development) +IDE | QT Creator or Visual Studio | NetBeans, Eclipse or IntelliJ IDEA +Web Deployment | No | Yes +Widgets | Lightweight | Lightweight +Pricing (Monthly no discounts) | 350 USD | 19 USD – 399 USD + Free +App Distribution | Only with active subscription | Perpetual + +### In Detail + +#### Language + +While QT supports QML (an XML flavor) with JavaScript bindings. QT at it’s base is C based. If you need to integrate a native widget like Googles native maps or similar capabilities you need to do this via C. + +This might be challenging as most of the integration documentation for various libraries is in Java, Objective-C. +Binding an iOS/Android SDK to QT might not be trivial. C++ isn’t garbage collected or “safe” and is a challenging +language for novices. + +Codename One uses Java for everything with all of the typical Java advantages (GC, safe memory etc.). When +integrating with native code Codename One generates “stubs” for the various platforms allowing developers to +write native Objective-C, Java (Android flavor), C# etc. code. + +This makes integrating with native OS capabilities far simpler as developers can literally copy and paste sample +code from the SDK vendor. + +#### Pricing & Rights + +QT is free for open source GPL projects. For every other case it’s priced at 295USD per developer. + +Codename One has a free commercial license and a full license starts at 19USD. + +Codename One sees the apps as owned by you, once built you are free to sell and redistribute them even after canceling a subscription. QT [requires](https://www.qt.io/faq/) licensing fees for distribution. If you stop paying the monthly licensing fee you need to stop distributing the applications you’ve already built. + +#### Cloud Build + +Codename One’s cloud build capability is unique. It allows developers to build a native application using the +Codename One cloud servers (Macs for iOS, Windows machines for Windows etc.) This removes the need to +own dedicated hardware and allows you to build native iOS apps from Windows and native Windows apps +from your Mac or Linux machine. + +This makes the installation of Codename One trivial, a single plugin to install. This isn’t true for development +environments that don’t use that approach. + +#### IDE + +QT has its own custom IDE with GUI builder. It also has a plugin to support Visual Studio which is quite popular +in the C++ developer community. + +Codename One integrates with all major Java IDE’s thru a standard plugin. The plugin delivers the simulators +and visual tools for Codename One as well as the device building capabilities. + +#### Web Deployment + +QT is very portable and so is Codename One. Both support many platforms but there is one that Codename One +can support that QT might find unreachable: JavaScript. + +Codename One supports the process of compiling an application (threads and all) into a JavaScript application +that can be hosted on the web. This is done by statically translating the Java bytecode to JavaScript obfuscated +code. + +#### Widgets + +The one point of similarity between QT and Codename One is that both frameworks take the lighweight widget +approach for greater flexibility and portability. However, as far as I can tell only Codename One supports lightweight/heavyweight mixing. + +Integrating a component like Goolge Maps into QT and drawing on top of it will require a lot of work. This is seamless in the current version of Codename One. + +### Property Cross Comparison + +The PropertyCross demo was built as a tool that allows us to compare two cross platform frameworks, as such +there are versions of the demo for many such platforms. You can check out details of the Codename One +implementation [here](/blog/property-cross-revisited.html). The github repository for this demo +is [here](https://github.com/codenameone/PropertyCross/). + +The [QT version of property cross](https://github.com/tastejs/PropertyCross/tree/master/qt) includes 3 projects: +– The main application QML UI – this includes code that is mostly declarative but quite a lot of it. It defines the UI +of the application and not much more +– The lib directory includes the CPP files and header files for the project +– A special test project that we’ll ignore for now as this isn’t covered in other discussions + +It’s pretty great that QT doesn’t require separate projects for every OS. It does have some theme directories but +most of the code including the UI is common. This is because QT and Codename One share a lightweight +architecture that increases portability. + +The code isn’t as verbose as some other implementations it is roughly 2x-3x larger than the Codename One +project in lines of code. The project seems to be missing the application launcher screenshots and the icon files +for the various supported DPI’s. While most of the resources would probably be adaptable in a portable way +icons and splash screens probably won’t be. + +This is something that Codename One can handle seamlessly thanks to the build servers but QT might have an +issue with. + +### Final Word + +Our opinions are obviously biased but I think we did a reasonably fair comparison. I actually like and respect QT +which makes it a great candidate for comparison. + +If you think we misrepresented Codename One or QT in any way let us know in the comments. + +Please use the comments section for suggestions of future comparison segments. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — April 30, 2016 at 8:37 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22630)) + +> bryan says: +> +> Gluon vs CN1 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Shai Almog** — May 1, 2016 at 4:39 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22641)) + +> Shai Almog says: +> +> I won’t blog about Gluon right now. It’s +> not a “real” product with shipping mobile apps. Comparing it to us would +> present it in a light where real apps can be built with it where in +> fact it is so inherently broken that I can’t find a single good thing to +> say about it. +> +> I don’t want to write a comparison to a +> product that I can’t say anything positive about. Gluon is so +> problematic I can’t even call it a real product as much as a mish mash +> salad of half baked technologies. It’s a proof of concept based on +> hugely complex 3rd party code that can’t possibly be understood by the +> guys shipping it. +> +> It is based on Java FX, the only reason +> that still exists is because Oracle is a corporate hoarder incapable of +> throwing anything away. FX is dead on the desktop and Oracle made the +> smart business move of not releasing it to mobile as it is technically +> unworkable in mobile. This was proven by Adobe who had a similar +> architecture fail on mobile regardless of Apple (it failed on Android +> too). 3rd party Scene Graph implementations are REMARKABLY hard to tune +> in a performant way and integrate with mobile GPUs/native widgets. +> Oracle who had some of the most amazing graphics developers ever +> understood that this is impratical. +> +> Their VM used to be +> RoboVM on which performance still sucked and it was a VERY FAST AOT VM. +> Now that RoboVM is dead their alternative is OpenJDK which is +> interpreter based… How can someone who even suggest an interpreter for +> something as complex and slow as a graphics intensive mobile +> scene-graph engine be taken seriously? +> +> While +> they are focused on re-inventing this HUGE amount of code that they +> can’t possibly test properly (e.g. [java.net]() can’t be implemented +> correctly on iOS, sqlite on Android/iOS is totally different etc.) they +> are also picking up the scene builder, custom widgets and IDE plugins… +> They will have to also pick up a VM as none of the existing options can +> compete with RoboVM in terms of speed/breadth. RoboVM was too big for +> one company to maintain and Gluon is already over stretched by a few +> miles so what’s another insurmountable challenge to the pile… +> +> This +> shows lack of focus and understanding of the scope of work required. I +> can’t possibly take a company that takes up something clearly +> impractical and unworkable as serious. +> +> To make matters +> worse they have no viable business model. This means they rely on +> consulting fees and nag screens which is a very problematic method of +> building a sustainable business. RoboVM took a similar path of +> unsustainable business practice and that ended in the only place it +> could end. We like to think that those things don’t matter but if you +> want your technology to exist tomorrow you need it to be open, +> accessible, understandable and have a viable long term business model. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **bryan** — May 1, 2016 at 12:49 pm ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22790)) + +> bryan says: +> +> That’s a pretty good comparison 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Johan Vos** — May 2, 2016 at 9:14 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22519)) + +> Johan Vos says: +> +> If you want an answer without lies and FUD, feel free to contact us (Gluon) directly. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Shai Almog** — May 2, 2016 at 9:17 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22809)) + +> Shai Almog says: +> +> FUD is subjective but which part of my response is untruthful? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Felix Bembrick** — May 2, 2016 at 11:15 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22848)) + +> Felix Bembrick says: +> +> Which part is untruthful? Just the bit after “I won’t blog about Gluon right now” which even itself was a lie. +> +> Underestimating Gluon and the passionate people like me who support what they are doing will be your own downfall. +> +> Pride comes before a fall and given the humungous amount of pride that’s on display here I would anticipate your fall will be of nuclear proportions. +> +> JavaFX rules and Gluon is making it rule even better. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Shai Almog** — May 2, 2016 at 11:24 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22721)) + +> Shai Almog says: +> +> Not blog, comment. Big difference. +> +> I’ve worked in this industry and at Sun for quite a while (90’s). Seen these things come and go and I know the complexities involved in both JavaFX on mobile and in mobile Java in general (not to mention Sun/Oracle politics). You are conflicting pride and expertise. +> +> I know my stuff and I advocate it, that’s pride. You are looking at my expert opinion and discarding it as “just pride” well… That’s the kettle… +> +> It’s true that I am discounting you just like I did RoboVM which ended pretty much where I predicted which is the exact reason we chose not to go with them in 2013. +> +> When you say JavaFX “rules” you might as well spell that with a Z. That is not a fact and shows the level of thought you put into this. Please feel free to disprove a single factual point I made above… +> +> E.g. let me give you a nugget, FX fans constantly talk about FX going into VW and making a splash. Guess what, Codename One has shipped in millions of cars for years and we didn’t even mention that ONCE! +> +> If you think FX will pick up because of one deal or another I suggest you take your emotional attachment. Put it in a box and take a step backwards. You might like FX, it’s an elegant API designed by brilliant people for whom I have the utmost respect. But that doesn’t change one iota of the facts I wrote above. I’m waiting anxiously for an itemized list of “lies”. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Felix Bembrick** — May 2, 2016 at 11:25 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22857)) + +> Felix Bembrick says: +> +> BTW, just to fill those massive voids known as ignorance, are you even aware that there are already 2 forks of RoboVM so the technology is actually more alive than ever? +> +> And, gosh, of course Gluon never realised that a fully interpreted version of Java will never be viable on mobiles! +> +> You are basically calling Johan an idiot and the one thing that I am more certain about him than anything else is that he ain’t no idiot! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Shai Almog** — May 2, 2016 at 11:28 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-21484)) + +> Shai Almog says: +> +> One minor thing I forgot to mention. I actually worked with the JavaFX +> Script team to get JavaFX onto mobile. I know a thing or two here. Also +> consulted to the JavaFX embedded team lead on graphics and GPU usage… +> +> I’m well aware of these forks. I’m also well aware that the RoboVM team claimed that Java 9 compatibility which came after the forks was the hardest thing they worked on since building RoboVM itself. So you are saying they lie? +> +> I’m calling Johan ignorant and arrogant. A desktop developer walking into mobile expecting things to work in the same way and picking up a HUGE pile of code expecting it to “work” in production. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Felix Bembrick** — May 2, 2016 at 11:29 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22448)) + +> Felix Bembrick says: +> +> Oh well, all I can say to you is “keep digging”. That’s already a mighty big sink hole that your life’s investment is about to fall into… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Felix Bembrick** — May 2, 2016 at 11:31 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22610)) + +> Felix Bembrick says: +> +> Do you even know that Gluon products are already working and working very well on mobiles? I mean never let the truth get in your way of dissing a Java Champion or a vastly superior technology to whatever it is that you’re peddling… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Shai Almog** — May 2, 2016 at 11:34 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22467)) + +> Shai Almog says: +> +> Being a Java champion (I’m only a rockstar as I don’t suck up to Jim) I couldn’t care one iota. +> +> Running something on a device is miles away from shipping a product or passing a TCK. +> +> I’m invested but you still fail to show one thing that was a “lie” in my post. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Felix Bembrick** — May 2, 2016 at 11:35 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22577)) + +> Felix Bembrick says: +> +> And I am sorry, I admit that cannot disprove any factual comments you have made. +> +> But that’s because i cannot disprove something which is yet to exist. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Felix Bembrick** — May 2, 2016 at 11:39 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22631)) + +> Felix Bembrick says: +> +> Gosh, did I use the word “pride”? I should have used “arrogance”, “delusion” and/or “narcissism”. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Shai Almog** — May 2, 2016 at 11:44 am ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22642)) + +> Shai Almog says: +> +> So let me get this strait. +> Johan comes on our blog. Calls me a liar for posting a factual true opinion made by myself with my bias clearly evident and displayed… +> +> And you then come off and claim that I somehow am unaware of “facts” that I am clearly aware of and I’m not OK? +> +> I’m biased true… I might have a cognitive dissonance. That is always true… +> +> Narcissism? +> +> You would laugh if you actually knew me. +> +> Arrogance? +> +> You betcha I’m arrogant. Comes with being an expert too. +> +> Delusion? +> +> I can’t possibly tell that about myself. However, I suggest you take a step backwards and evaluate if maybe the roles are reversed here. +> +> FX couldn’t succeed with all the resources of Sun/Oracle behind it, you can claim that I’m arrogant and delusional… But you are insane if you don’t take up these mantles yourself…. +> +> Gluon is taking up not Just FX, but the whole ecosystem and is now also picking up the VM work, IDE integration and all the slack left by RoboVM. We have people who know every piece of Codename One inside out. We worked on it since 2007 and we know everything there is to know. You guys are dealing with a HUGE black hole of software some of which still doesn’t exist and you are trying to sell it as if it’s a sellable product. But I’m arrogant and delusional? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Felix Bembrick** — May 2, 2016 at 12:29 pm ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22868)) + +> Felix Bembrick says: +> +> Well, you have still failed to even concede that your very first statement “I am not going to blog about Gluon right now because the babbling that follows is commenting, not blogging as the two are radically different polar opposite concepts” was a lie. +> +> And that was the high point of your babbling. +> +> It was all downhill from there, just like your company’s future bottom line. +> +> And to say that I would laugh if I actually met you is a given as I have basically been laughing my head off since you started firing blanks at Johan. +> +> And, you might think you are the smartest and most experienced person with these technologies on the planet but that’s only true because you’re on some other planet than the rest of us. +> +> Let me just say you have no idea who you are feebly trying to trade blows with. I too worked at Sun (but that wasn’t challenging enough). I have also worked on what was recently voted the second best animated film of all time in terms of the rendering and animation quality. I have optimised scene graphs before. I know more about GPU technology than you do about how to behave like a tool. Johan and I could together take down your entire company all by ourselves if you continue to motivate us to do just that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Shai Almog** — May 2, 2016 at 1:23 pm ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22791)) + +> Shai Almog says: +> +> Great to hear that you worked at Sun. Did you do mobile too? +> +> Good luck to you guys with gluon, I’m sure you will reach the same level of market success as FX. +> +> Notice that if we fail you will fail too but the opposite isn’t true. We are the established leader in the Java mobile WORA tools but to take that position you need to surpass in acquisitions not take business from us. I hope you have someone who understands how the business side of things works at your company. +> +> We are not your competitor just like you are no threat to us. At most you could in theory slow our growth but if we go down in sales it means the market is shrinking which is bad for us but horrible for you as you aren’t yet established. +> +> I suggest you focus first on understanding “what the market is”, it sounds like a “stupid business speak” but I suggest you understand these concepts if you want to succeed. Then take a step back and objectively compare the end user/developer proposition of our respective tools. You will notice that you guys target a very different demo/value proposition. If you carry that analysis to its full extent you will also see what I saw in my first meeting with Niklas at JavaOne 2013. There is no business model for your approach other than consulting. +> +> Consulting can be moderately profitable, but you can’t sustain long term platform development on consulting fees. Eventually you need to pick and choose if you are a consulting shop or a startup and at that point you need to sit down with someone who understands business and try to imagine the growth that’s achievable in realistic scenarios. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Felix Bembrick** — May 2, 2016 at 6:31 pm ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22875)) + +> Felix Bembrick says: +> +> Thanks for your advice. It’s mostly very accurate and worth reading. It’s just the bit after “Glad to hear that you worked at Sun” that has that “babbling” quality you do so well that I will wisely ignore. +> +> Would you appreciate me endorsing you for the skill of babbling? You are clearly at the elite level. +> +> You know, I am fairly sure Johan is a lot like me in one aspect. The more people tell us that something “can’t be done”, the more motivated we become to prove such people wrong (which seems a little superfluous in your case). +> +> So, let the Hunger Games begin. I’ll play the part of Katniss and you can continue in your role as Snow (or Coin). +> +> The very name of your company suggests you are so narrow minded that you think you are the only technology that anyone ever needs. One size fits all. You are so disrespectful and arrogant to your competitors that I am surprised if there’s room in your office space for anything more than just your ego. +> +> But I love to see this. You are such a classic example of the kind of CEO that thinks their business model is “Competitors? What competitors?”. +> +> You will only see them when you are broke, unemployed and living in a trailer park. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Shai Almog** — May 2, 2016 at 7:16 pm ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22812)) + +> Shai Almog says: +> +> Like I said before takes one to know one but I get that you don’t like me and I don’t mind one bit. +> +> Notice a big difference about our approaches, you are writing in our +> blog deriding me with insults on a personal level. Yet I don’t kick you +> out. That’s pretty evil of me. I’m just mean in that way…. +> +> Codename One is about unifying everything to a single technology that hides the complexity not using a single technology for everything. But feel free to concentrate all your anger at me and use me as your motivation. +> +> You didn’t get what I said at all. You don’t compete with us. If you do then you are in big trouble. +> We are profitable but we’re not the leader in cross platform by a long shot. We are not even the leader in mobile Java (that’s Android). If you are going after us then you are going after a small market share relatively and that’s “stupid”. I know business books are boring but I suggest picking a few up and learning about “go to market” strategies. But obviously you treat everything I say as evil and malicious so I’m just trying to waste your time with an understanding of how business works and how to define your competitors properly to confuse you. +> +> But if it helps you work at night with the dream of somehow putting the big bad me and my family into the streets because I’m such an awful human being who dares to think you are wrong and is wasting his time in his own blog post explaining that to you then feel free to concentrate your anger and contempt at me 😉 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Felix Bembrick** — May 2, 2016 at 8:19 pm ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22849)) + +> Felix Bembrick says: +> +> If I offered you a tissue, would that make you feel any better? +> +> And please stop assuming you know stuff that neither I nor seemingly anyone else could possibly know. +> +> I don’t need lectures from you on business, strategic planning or on anything for that matter (except of course on babbling mastery where I admit you have me beaten). +> +> And insults? Have a look at where they started. It was only then that I even decided to get involved (regrettably). +> +> But thanks for showing such extraordinary tolerance and generosity for not booting me out of *your* forum. I mean, it’s not like that would appear as a concession of defeat or anything like that +> +> Everyone knows it’s just because you’re such a kind hearted, polite, respectful and open minded person who knows more about business than Warren Buffet and has an IQ of 250. +> +> Oh, and who doesn’t suck up to Jim 😉 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Shai Almog** — May 2, 2016 at 8:38 pm ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-22722)) + +> Shai Almog says: +> +> Despite your attitude towards me I wish you no harm, on the contrary I honestly do hope that you guys do well. I don’t think it will hurt our business just like RoboVM didn’t impact our business much neither when they launched nor when they left (just made CPM and SEO slightly more expensive). +> +> I think you need to re-evaluate your words and the line between a strong disagreement and animosity. +> +> I didn’t “start” I wrote a factual opinion in a comment response to a question posted to our blog. Your colleague came in, called me a liar without basis. You then come in with name calling and repeated assaults on what you perceive as my personality flaws. +> +> No I don’t suck up to Jim and never have which is why we never got free publicity from Oracle despite paying full price for a booth at J1 a couple of years ago and speaking for years. +> +> Unlike you I don’t think you guys are stupid, I think you are wrong but not stupid. +> +> You obviously ignore everything I say so lets cut it here. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + + +### **Kyri Ioulianou** — June 15, 2016 at 5:36 pm ([permalink](https://www.codenameone.com/blog/comparing-qt-and-codename-one.html#comment-24212)) + +> Kyri Ioulianou says: +> +> You destroyed this guy +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-qt-and-codename-one.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/comparing-xamarin-and-codename-one.md b/docs/website/content/blog/comparing-xamarin-and-codename-one.md new file mode 100644 index 0000000000..79389fe5da --- /dev/null +++ b/docs/website/content/blog/comparing-xamarin-and-codename-one.md @@ -0,0 +1,376 @@ +--- +title: Comparing Xamarin and Codename One +slug: comparing-xamarin-and-codename-one +url: /blog/comparing-xamarin-and-codename-one/ +original_url: https://www.codenameone.com/blog/comparing-xamarin-and-codename-one.html +aliases: +- /blog/comparing-xamarin-and-codename-one.html +date: '2016-05-11' +author: Shai Almog +--- + +![Header Image](/blog/comparing-xamarin-and-codename-one/compare-to-xamarin.jpg) + +Last time around we compared [Codename One to QT](/blog/comparing-qt-and-codename-one.html) and this +time around I’d like to compare Codename One to the 800 pound gorilla: Xamarin. Xamarin is an amazing product +that I [contrasted with Codename One in the past](https://forums.xamarin.com/discussion/55129/comparing-xamarin-to-other-cross-platfrom-frameworks-codename-one?) +but this is worth repeating. + +On it’s surface Xamarin might seem like a similar tool to Codename One using C# used instead of Java, but this +is misleading as the tools are so different conceptually they have very little in common. + +__ | We updated this comparison after the initial publication to include the additional Property Cross section +---|--- + +### Background + +Xamarin was founded by Nat Friedman and Miguel de Icaza famous for the GNOME desktop environment, +Mono and Ximian. + +Xamarin launched in 2011, during those years xcode was a very primitive IDE. It didn’t have ARC and had quite +a few problems. Xamarin offered the ability to write native iOS apps in C# with garbage collection and the other +great features allowed by C#. + +Xamarin didn’t abstract the API much at the time and effectively provided mappings between C# and native +API calls. It also produced a similar version for Android which did the same. In that sense Xamarin eschewed +the write once run anywhere mantra in favor of a common set of business logic coupled with separate UI/native +code/resources. + +__ | When we say “native code” in the Xamarin context that usually means C# code that uses the native OS API, +the Codename One context of native code refers to actual OS native languages e.g. Objective-C on iOS +---|--- + +As the company grew it built the Xamarin Forms solution on top of the existing infrastructure which provides +something closer to write once run anywhere. Since native widgets were used for Xamarin Forms this posed +a problem as there are inherent insurmountable differences between the iOS/Android widget API’s. + +#### Microsoft Purchase + +Xamarin was purchased by Microsoft in February 2016 and integrated into visual studio. Most of +it’s products were open sourced as part of this purchase. + +### At a Glance + +Category | Xamarin | Codename One +---|---|--- +Language | C# | Java +IDE | Visual Studio/Xamarin Studio | NetBeans, Eclipse or IntelliJ IDEA +Cloud Build | No (requires Mac & Windows for full OS support) | Yes (can work on Linux for iOS development) +Web Deployment | No | Yes +Widgets | Heavyweight | Lightweight +Portability Strategy | Cross platform, sub projects | WORA + Native Interfaces (one project) + +__ | Xamarin requires a Mac for the iOS native app but you can develop on a Windows machine and have a Mac +machine in your office to which Xamarin will connect to do the actual native work +---|--- + +### In Detail + +#### Language & IDE + +I’m not a fan of C# or visual studio but C# is a decent language as is Java especially with version 8. Since both +languages have similar core concepts the differences come down to personal taste more than anything. + +The same is true for Visual Studio vs. any of the popular Java IDEs (Eclipse, IntelliJ & NetBeans). These are all +mature, powerful IDE’s that include anything you might need. + +##### Native Language + +While as a language C# might be a decent option, it is an alien to the two leading mobile platforms. + +Android’s “native” language is Java. The UI widgets in Android are implemented in Java, which effectively means +that if you write code in C it will perform slower than Java code as it would need to pass thru JNI. C# +code can’t be implemented on top of the current Android VM and effectively needs to pass thru JNI +back and forth repeatedly. + +This overhead is very noticeable when working with heavyweight widgets as the communication between the widget +and the logic needs to be very frequent. In that sense C# is less native than Codename One which is just implemented +directly on top of the native layer. + +On iOS the story is different, Xamarin implements the whole toolchain effectively hiding Apples tools +completely. This is a very powerful abstraction but it sometimes creates another layer of complexity. E.g. when +Apple introduces a new idea such as bitcode or a new profiling tool Xamarin can’t fully leverage such a tool. It has +it’s own set of tools but they will always be second class citizens on Apples platform. + +Codename One uses the open source [ParparVM](https://github.com/codenameone/CodenameOne/tree/master/vm) +to translate Java bytecode to a native C xcode project on Mac OS. This effectively creates a native iOS project +and allows you to write native Objective-C code write into that project. In a sense this is “more native”as it ends +up using a greater portion of the “officially supported toolchain”. + +Xamarin isn’t needed on Windows as Microsofts native tools can be used to provide portability to that platform, there +Microsoft is the true native leader by definition. + +#### Cloud Build + +Codename One’s cloud build capability is unique. It allows developers to build a native application using the +Codename One cloud servers (Macs for iOS, Windows machines for Windows etc.) This removes the need to +own dedicated hardware and allows you to build native iOS apps from Windows and native Windows apps +from your Mac or Linux machine. + +This makes the installation of Codename One trivial, a single plugin to install. This isn’t true for development +environments that don’t use that approach. + +Xamarin is far more “low level” than Codename One. Xamarin assumes you have deep platform knowledge e.g. +you have to understand the Android activity API and lifecycle in order to build a Xamarin Android app. You need +to understand the `ViewController` to build a Xamarin iOS app. You don’t need +to understand either one of those in order to build a Codename One application. + +Both platforms allow access to the underlying native code with a different underlying philosophy as explained below. + +__ | Knowledge of the native platform is less essential with Xamarin Forms but is still expected and deemed as +an advantage by the Xamarin team. This highlights the core conceptual/philosophical differences between the platforms +---|--- + +#### Web Deployment + +Xamarin supports almost all of Codename One’s supported platforms either directly or thru Microsofts Visual +Studio tools. However, it doesn’t support building native JavaScript web applications. + +Codename One supports the process of compiling an application (threads and all) into a JavaScript application +that can be hosted on the web. This is done by statically translating the Java bytecode to JavaScript obfuscated +code. + +__ | There are some early stage efforts to bring XAML to JavaScript but none are at a mature stage of supporting +complex notions like threads +---|--- + +#### Widgets + +This is probably the biggest difference between Xamarin and Codename One. + +Xamarin exposes the underlying UI API completely to the developer. This is exposed so completely that a developer +can literally use the native iOS/Android visual design tools to build layouts (that naturally **won’t be portable**). + +Codename One uses a lightweight widget approach where it draws the component hierarchy but allows embedding +of native widgets for specific requirements (HTML, media, text etc.) this. The difference between these two approaches +is highly documented and has been debated since the days of smalltalk (think Swing vs. SWT/AWT). + +Heavyweight architecture is closer to the way the native OS behaves and as a result is inherently less portable +and not as flexible. This is a tradeoff that some developers are willing to accept in order to be “more native”. + +Heavyweight is sometimes deemed “faster” by its proponents but the technological basis for such claims is flawed as +these widgets are harder to measure realistically across platforms and optimize properly. + +##### Xamarin Forms + +Xamarin also supports Xamarin Forms which uses XAML to allow sharing most UI code between various platforms +by picking the lowest common denominator approach to the UI. Unlike Codename One the Xamarin Forms approach +still uses native code and assumes some native access. + +It isn’t designed as a complete WORA (Write Once Run Anywhere) solution but rather as a middle ground solution. + +Notice that with Xamarin Forms you will not be able to use some native OS capabilities such as the native OS +GUI builders for obvious reasons. + +#### Portability Strategy + +Codename One uses a single project that works everywhere. When you need access to native code this native +code is hidden by the native interfaces abstraction that allow that single project to remain “clean” of native code. +By default no native code of any type is necessary to build a Codename One application. + +Xamarin requires a “pseudo native” project (still written in C#) to represent the lifecycle, resources and other elements +of the various supported platforms. By default this will include a lot of the platform specific code such as UI etc. +with the exception of Forms apps where there will be less code in the separate projects. + +These might seem like small differences but they hide a major core difference. Codename One tries to abstract the +aspect of platform native differences and Xamarin pushes it to the forefront. + +#### Microsoft + +A big selling point for Xamarin is the Microsoft acquisition positioning it as a major player backed by the full weight +of Microsoft. Microsoft has repeatedly abandoned technologies in which they invested a great deal of money +e.g. Windows Phone 7, Silverlight etc. It also demonstrated this recently by discarding RoboVM without the +curtesy of opening its source code. + +Xamarin is free in order to gain traction and serve Microsofts market goals. As long as those goals align with +the goals of developers using Xamarin this is a good thing. However, since this is a market MS competes in +it is not an impartial player. + +No one can tell at this time whether the purchase will have a negative effect on the future development of Xamarin. +So far the Microsoft purchase has been largely a positive thing with the exception of the RoboVM issue. + +### Property Cross Comparison + +The PropertyCross demo was built as a tool that allows us to compare two cross platform frameworks, as such +there are versions of the demo for many such platforms. You can check out details of the Codename One +implementation [here](/blog/property-cross-revisited.html). The github repository for this demo +is [here](https://github.com/codenameone/PropertyCross/). + +Xamarin has two cross platform implementations for property cross a +[regular app](https://github.com/tastejs/PropertyCross/tree/master/xamarin) and a +[mvvm version](https://github.com/tastejs/PropertyCross/tree/master/xamarinmvvmcross). +Both don’t use Xamarin Forms which is a shame since it would probably be closer to what we offer with Codename +One but it’s still a good overview of the differences. + +Lines of code are a pretty bad measurement of the overall quality of a framework, however having said that they +do provide some indication of the verbosity and Xamarin is far more verbose than Codename One. E.g. +looking at the +[MVVM model implementation alone](https://github.com/tastejs/PropertyCross/tree/master/xamarinmvvmcross/PropertyCross.Core/ViewModels) +we can see that it has more lines of code than the entire Codename One implementation! + +The Xamarin implementations are really 4 implementations for iOS, Android, Windows Phone & a portable common +project. This effectively means that the Xamarin implementation requires a deep understanding of the native platforms +since it’s in essence native programming. + +__ | The Xamarin Forms implementation would still require such a structure although a greater portion of the code +would reside in the common project +---|--- + +This also means you will need to either use the iOS tools to build a UI or deal with the screenshots, icon resolutions +& DPI changes for the various device types. E.g. on iOS you would need images using the `@` notation but on +Android you will need to divide the images to the DPI directories creating a lot of work on resource maintenence +which just doesn’t exist in Codename One. + +In that sense PropertyCross is probably a poor demo as it doesn’t contain many resources that need maintenence. + +### Final Word + +As usual our opinions are biased but I think we presented a reasonably fair evaluation. Xamarin is an +impressive tool that is quite different inherently from Codename One & we hope we highlighted those +differences fairly. + +If you are looking to write a native application you like C# & don’t mind dealing with platform differences it is a +compelling option. However, if you prefer Java and portability is key I think we have a far more compelling story. + +If you think we misrepresented Codename One or Xamarin in any way let us know in the comments. + +Feel free to use the comments section for suggestions of future comparison segments. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **J Master** — May 13, 2016 at 9:50 am ([permalink](https://www.codenameone.com/blog/comparing-xamarin-and-codename-one.html#comment-22538)) + +> J Master says: +> +> Interesting, less than 300 stars for a github compare to 32,970 developers? Can it be compile to Swift code instead of C? +> +> 120,000,000 is based from which figure? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-xamarin-and-codename-one.html) + + +### **Shai Almog** — May 14, 2016 at 3:19 am ([permalink](https://www.codenameone.com/blog/comparing-xamarin-and-codename-one.html#comment-22663)) + +> Shai Almog says: +> +> We migrated from Google code at the last possible instance which explains the low star count. +> +> By default we include device counting code in builds (this can be disabled) so we composed that number from verified installed which we then correlated to actual appstore installs and to apps/devices where we know this was developed to come up with a composite number. The number is actually much larger by now but we didn’t get around to go thru this process to update it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-xamarin-and-codename-one.html) + + +### **Siva Mamidi** — June 2, 2016 at 8:32 pm ([permalink](https://www.codenameone.com/blog/comparing-xamarin-and-codename-one.html#comment-22757)) + +> Siva Mamidi says: +> +> Very nice article and informative. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-xamarin-and-codename-one.html) + + +### **Benjamin Hamilton** — June 18, 2016 at 1:10 am ([permalink](https://www.codenameone.com/blog/comparing-xamarin-and-codename-one.html#comment-22613)) + +> Benjamin Hamilton says: +> +> From your article +> Android’s “native” language is Java. The UI widgets in Android are implemented in Java, which effectively means that if you write code in C it will perform slower than Java code as it would need to pass thru JNI. +> +> From Google +> [https://developer.android.c…]() +> +> JNI is the Java Native Interface. It defines a way for managed code (written in the Java programming language) to interact with native code (written in C/C++). It’s vendor-neutral, has support for loading code from dynamic shared libraries, and while cumbersome at times is reasonably efficient. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-xamarin-and-codename-one.html) + + +### **Shai Almog** — June 18, 2016 at 4:56 am ([permalink](https://www.codenameone.com/blog/comparing-xamarin-and-codename-one.html#comment-22941)) + +> Shai Almog says: +> +> That’s a common misconception. Check out this article from Chet & Romain two brilliant ex-Sun guys who are very deep in the Android GUI system development: [https://realm.io/news/romai…]() +> +> Copied from the source article: +> +> Avoid JNI +> +> Sometimes you need JNI, but not if +> you’re just using it out of convenience. Something interesting about JNI +> code: every time you cross the boundary between Java runtime and native +> there’s a cost because we need to validate the parameters and it has an +> impact on the GC behaviors. It can be pretty expensive, so when you do a +> lot of JNI calls, you might spend more time in the overhead of JNI than +> in the actual code. If you have old JNI code, you might want to revisit +> it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-xamarin-and-codename-one.html) + + +### **Marcin** — July 15, 2016 at 1:28 am ([permalink](https://www.codenameone.com/blog/comparing-xamarin-and-codename-one.html#comment-22793)) + +> Marcin says: +> +> Hello Shai, how about the Dependency Injection with Codename One? +> +> I tried to search for spec, examples or even searched for phrase “@Inject” through the Github examples. +> Is it possible to decouple code this way? +> +> Are there any other decoupling methods available like EventBus? +> +> It would be also really great to have CDI like producers, I mean annotations @Produces . Also some scopes… +> Is it possible with Codename One? +> +> And finally how about writting testible code with Codename One? +> It looks like I have to use lot of singletons like Display.getInstance()… or FaceBookAccess.getInstance()…. or static calls like LocationManager.getLocationManager().getCurrentLocation(). +> Could I simply inject those instead? Something like @Inject LocationManager? +> Singleton objects definiton could be marked with @Singleton annotation. Unfortunately I don’t see it there ([https://goo.gl/UhJDSY)]()). +> The reason I wan’t to inject this stuf is that I prefer simple UnitTests over long running Integration Tests. +> +> Regards, +> Marcin +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-xamarin-and-codename-one.html) + + +### **Shai Almog** — July 15, 2016 at 4:00 am ([permalink](https://www.codenameone.com/blog/comparing-xamarin-and-codename-one.html#comment-22801)) + +> Shai Almog says: +> +> Hi, +> no we don’t support DI since we don’t support reflection and bytecode manipulation isn’t trivial since it must be done statically with great care. It’s possible to do bytecode manipulation as Steve did with the POJO mapper: [http://www.codenameone.com/…]() but no one did it for DI. +> +> We don’t support JUnit etc. so you will need to use our test framework which includes a test recorder etc. I think a lot of the problems solved by DI are server problems and not as pertinent to the front end developer landscape. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-xamarin-and-codename-one.html) + + +### **Martin Grajcar** — September 9, 2017 at 1:26 am ([permalink](https://www.codenameone.com/blog/comparing-xamarin-and-codename-one.html#comment-23350)) + +> Martin Grajcar says: +> +> Dagger 2 uses no reflection at all, so in theory it must work. As this is the only relevant search result for “codenameone” and “dependency injection”, I’m afraid that nobody has really tried it yet. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-xamarin-and-codename-one.html) + + +### **Shai Almog** — September 9, 2017 at 7:13 am ([permalink](https://www.codenameone.com/blog/comparing-xamarin-and-codename-one.html#comment-23502)) + +> Shai Almog says: +> +> Steve did POJO mapping which is pretty similar, if you use bytecode manipulation tools it can work but DI isn’t as helpful in mobile client as it is in server code so there wasn’t as much demand. +> +> If you try it and run into difficulties just ask on stackoverflow (with the codenameone tag) or in the discussion forum. We’ll try to help. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomparing-xamarin-and-codename-one.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/completion-ios-7-update-and-the-20m-mark.md b/docs/website/content/blog/completion-ios-7-update-and-the-20m-mark.md new file mode 100644 index 0000000000..4c081dc60b --- /dev/null +++ b/docs/website/content/blog/completion-ios-7-update-and-the-20m-mark.md @@ -0,0 +1,177 @@ +--- +title: Completion, iOS 7 Update And The 20M Mark +slug: completion-ios-7-update-and-the-20m-mark +url: /blog/completion-ios-7-update-and-the-20m-mark/ +original_url: https://www.codenameone.com/blog/completion-ios-7-update-and-the-20m-mark.html +aliases: +- /blog/completion-ios-7-update-and-the-20m-mark.html +date: '2013-08-27' +author: Shai Almog +--- + +![Header Image](/blog/completion-ios-7-update-and-the-20m-mark/completion-ios-7-update-and-the-20m-mark-1.png) + + + + +[ +![Picture](/blog/completion-ios-7-update-and-the-20m-mark/completion-ios-7-update-and-the-20m-mark-1.png) +](/img/blog/old_posts/completion-ios-7-update-and-the-20m-mark-large-2.png) + + + +Exciting news this week, Chen FINALLY did what we procrastinated on for so long and wrote an auto-complete text field! + + +This is really easy to incorporate + +into your code, just replace your usage of TextField with AutoCompleteTextField and define the data that the auto complete should work from. There is a default implementation that accepts a String array or a ListModel for completion strings, this can work well for a “small” set of thousands (or tens of thousands) of entries. + + + + + +However, if you wish to query a database or a web service you will need to derive the class and perform more advanced filtering by overriding the + +filter method and the getSuggestionModel method. You might also need to invoke updateFilterList() if your filter algorithm is asynchronous. + + +Here is a sample of a simple auto-complete that doesn’t use the advanced features: + + +* * * + +As part of that feature Chen also added something very interesting to Form… Up until now the best way to draw on top of a Form was to create a glass pane create your own layered layout for the internal content pane. + + +Chen added a cool new method to form: + +getLayeredPane(). + + +Essentially a layered pane sits on top of your content pane and you can just place any component you want there just like you would in the content pane. Only difference is that it will be drawn on top of the content pane. Unlike the glasspane which is a drawing API and lacks interactivity the layered pane allows you to place pretty much any component there. + + + +** +iOS 7 Update +** + +According to the latest rumors Apple is about to release iOS 7 by September 10th, so here is a quick update on where we stand and what you need to know moving forward. + + +Just so we are 100% clear, all current builds work on iOS 7 devices. We have already migrated our devices to the latest beta’s and have verified that builds keep working! + + +However, iOS 7 is a major departure in terms of design and some application behaviors. The biggest change is the move to +[ +flat design +](http://sachagreif.com/flat-pixels/) +, Tope has a great blog post +[ +detailing some of the migration efforts +](http://www.appdesignvault.com/ios-7-update/) +from a designers perspective. + + +You can already update your user interface and theme to be more flat and modern (as well as your icon design etc.). + + + +We would ideally update some of our themes to match those expectations. + + +As people start migrating to OS 7 you might want to make your app OS 7 only and thus take advantage of the taller title area (the title area in OS 7 stretches behind the battery/time/network indicator) as well as some minor OS 7 tweaks and the default OS 7 look. To do that you will need to have your application compiled with XCode 5 which is currently in beta. We already tested this process and we will allow a build argument to use XCode 5 once the tools are released from beta. Naturally, our recommendation is that you do not use these tools until most users migrate (which I assume will be slow given how some people feel about iOS 7). + + + + + +** + +Traction, Testimonials & Trips + +** + + + +You might have noticed the big counter of installed devices we added to the home page, we are pretty thrilled having crossed the 20M device install base. Now lets work on adding a couple of zeros there… + + +We also added a testimonials popup to the home page (commented out due to an issue in Firefox), if you have a testimonial you would like to contribute to appear on our home page and an impressive public linked in profile we would really appreciate it + +if you take the time to +[ +write something about us +](/contact-us.html) +(please include the linked in public profile link). + + +I will be speaking at both JavaZone and JavaOne (NetBeans day) this year. So I will be in both Oslo and San Francisco, if any of you are coming to these conference or live in the area I’d love to meet, just contact us via the +[ +contact form +](/contact-us.html) +. + + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — August 29, 2013 at 3:45 am ([permalink](https://www.codenameone.com/blog/completion-ios-7-update-and-the-20m-mark.html#comment-21745)) + +> Anonymous says: +> +> just thought you should know, that the title to this post is different, from the title on the front page of the website +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcompletion-ios-7-update-and-the-20m-mark.html) + + +### **Anonymous** — August 29, 2013 at 3:50 am ([permalink](https://www.codenameone.com/blog/completion-ios-7-update-and-the-20m-mark.html#comment-21788)) + +> Anonymous says: +> +> Thanks Kevin! +> +> The dangers of Copy & Paste… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcompletion-ios-7-update-and-the-20m-mark.html) + + +### **Anonymous** — September 11, 2014 at 1:25 pm ([permalink](https://www.codenameone.com/blog/completion-ios-7-update-and-the-20m-mark.html#comment-22224)) + +> Anonymous says: +> +> Is there any setModel method to pass the autocomplete data other than putting it in the contructor +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcompletion-ios-7-update-and-the-20m-mark.html) + + +### **Anonymous** — September 12, 2014 at 6:12 am ([permalink](https://www.codenameone.com/blog/completion-ios-7-update-and-the-20m-mark.html#comment-22061)) + +> Anonymous says: +> +> No but you can override the filter method to get more elaborate filtering capabilities. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcompletion-ios-7-update-and-the-20m-mark.html) + + +### **Anonymous** — January 27, 2015 at 6:55 am ([permalink](https://www.codenameone.com/blog/completion-ios-7-update-and-the-20m-mark.html#comment-22294)) + +> Anonymous says: +> +> always saying “you can filter”. please show us one example.. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcompletion-ios-7-update-and-the-20m-mark.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/component-gallery.md b/docs/website/content/blog/component-gallery.md new file mode 100644 index 0000000000..dceb8b79f2 --- /dev/null +++ b/docs/website/content/blog/component-gallery.md @@ -0,0 +1,52 @@ +--- +title: Component & Layout Galleries +slug: component-gallery +url: /blog/component-gallery/ +original_url: https://www.codenameone.com/blog/component-gallery.html +aliases: +- /blog/component-gallery.html +date: '2016-02-14' +author: Shai Almog +--- + +![Header Image](/blog/component-gallery/component-gallery.png) + +As you know we’ve been working a lot on the docs both the developer guide and the JavaDoc’s, we nearly doubled +the amount pages in the developer guide and we did it without “cheating” (e.g. cramming more stuff, increasing font size). +You can see all that work in the [developer guide](https://www.codenameone.com/manual/) section but what I want +to discuss today is the new [Component Gallery](https://www.codenameone.com/javadoc/com/codename1/ui/package-summary.html) +& [Layout Gallery](https://www.codenameone.com/javadoc/com/codename1/ui/layouts/package-summary.html). + +Both of these are a result of the developer guide work; as we did that we mapped a lot of the work back into +the JavaDocs and eventually edited the `package.html` files to produce that level of detail. We’re particularly proud +of the fact that if you click almost any component or layout within those galleries you will see sample usage code +that should help you get started with anything you need. + +When writing this sample code we tried to reflect back on a lot of the requests that you guys made from us, so things +such as dynamically downloading images to lists, `ImageViewer` etc. are all covered. Carousel UI with the `Tabs` +component and even trivial things such as making a `Button` look like a link. + +This take a lot of effort to do so please provide us as much feedback as you can on the process, e.g. on my last +post a developer asked a question related to `Table`. The answer to that question is now (thanks to him) in the docs. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Sadart** — February 17, 2016 at 12:35 pm ([permalink](https://www.codenameone.com/blog/component-gallery.html#comment-24201)) + +> Sadart says: +> +> Good job done. Docs are now extremely good for getting sample codes. Time saver! I had to redo the downloaded images on a form to use imageviewer and I have been ignoring it for ages. The initial codes in the old docs wasn’t clear enough for me. I can now implement it with ease. Thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcomponent-gallery.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/composite-animations.md b/docs/website/content/blog/composite-animations.md new file mode 100644 index 0000000000..a0005db2d1 --- /dev/null +++ b/docs/website/content/blog/composite-animations.md @@ -0,0 +1,61 @@ +--- +title: Composite Animations +slug: composite-animations +url: /blog/composite-animations/ +original_url: https://www.codenameone.com/blog/composite-animations.html +aliases: +- /blog/composite-animations.html +date: '2016-07-31' +author: Shai Almog +--- + +![Header Image](/blog/composite-animations/title-area-animation.gif) + +When we announced Codename One 3.4 we also announced a major animation overhaul. This was an important milestone that we didn’t fully actualize until this past week…​ + +Up until now animations in Codename One consisted of a fixed set of animations you could perform, e.g. if I want to move a `Component` from one place to another I could do an `animateLayout`. + +When I want to do multiple animations in a sequence I can chain them using the `AndWait` version or thru callbacks etc. + +This seems like it should be enough but it sometimes isn’t, e.g. if I have two or more containers and I want them to animate layout together, or if I want an animation to both animate the position and style of a component! + +To solve this we introduced the [ComponentAnimation](https://www.codenameone.com/javadoc/com/codename1/ui/animations/ComponentAnimation.html) class way back in 3.4. We now have new API’s that return `ComponentAnimation` instances that we can subsequently chain together e.g. this code is from the upcoming kitchen sink demo: + + + ComponentAnimation cn2 = createStyleAnimation(newUIID, 1000); + ComponentAnimation cn1 = createAnimateLayout(1000); + return ComponentAnimation.compoundAnimation(cn1, cn2); + +This code is within a subclass of `Container` so both methods are a part of `Container`. This code will result in an animation that both changes the style of the container as well as its layout! + +We’ve added five methods that create this type to container: + + + public ComponentAnimation createAnimateLayout(int duration); + public ComponentAnimation createReplaceTransition(Component current, Component next, Transition t); + public ComponentAnimation createAnimateHierarchy(int duration); + public ComponentAnimation createAnimateHierarchyFade(int duration, int startingOpacity); + public ComponentAnimation createAnimateLayoutFade(int duration, int startingOpacity); + +__ | `createStyleAnimation` has been around since 3.4 so it isn’t listed, but we fixed a some bugs there…​ +---|--- + +You will notice that there are no `AndWait` version since you add these animations to the animation queue thru the [AnimationManager](https://www.codenameone.com/javadoc/com/codename1/ui/AnimationManager.html) API which has both `addAnimation` & `addAnimationAndBlock` allowing both use cases. + +The code above uses the `compoundAnimation` static method to merge together animations (you can merge any number of animations not just two). You can also use the `sequentialAnimation` method to merge an animation sequence which might be more convenient than `AndWait` or `AndBlock`. + +### Published Developer Guide On Amazon + +On an unrelated subject we published the developer guide thru the Kindle book store +[here](https://www.amazon.com/Codename-One-Developer-Guide-Android-ebook/dp/B01JG0O3CK/). It’s the +same as the free PDF developer guide but it seems we can’t publish for free on Amazon. + +We’d appreciate customer reviews though and if you can help us promote it to drive awareness of Codename One. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/connecting-to-a-mysql-database-part-2.md b/docs/website/content/blog/connecting-to-a-mysql-database-part-2.md new file mode 100644 index 0000000000..9b2367fd99 --- /dev/null +++ b/docs/website/content/blog/connecting-to-a-mysql-database-part-2.md @@ -0,0 +1,553 @@ +--- +title: 'Connecting to a MySQL Database from Codename One Part 2: Pure Java' +slug: connecting-to-a-mysql-database-part-2 +url: /blog/connecting-to-a-mysql-database-part-2/ +original_url: https://www.codenameone.com/blog/connecting-to-a-mysql-database-part-2.html +aliases: +- /blog/connecting-to-a-mysql-database-part-2.html +date: '2016-11-28' +author: Steve Hannah +--- + +![Header Image](/blog/connecting-to-a-mysql-database-part-2/connecting-mysql-to-codenameone.jpg) + +In my last post I demonstrated how to integrate a MySQL database into a Codename One app using Xataface as a web service layer. In this installment, I’m going to demonstrate how we can build an equivalent app using a Java web service layer. + +## Requirements + +For this tutorial, I’ll be using NetBeans 8.1 and its bundled GlassFish 4.0 container. If you don’t already have a MySQL database set up, then I recommend you install XAMPP [XAMPP](https://www.apachefriends.org/index.html), as it provides a double-clickable installer for Mac and Windows and an easy administration console. + +## The Database + +The following setup instructions are identical to those in the previous post. They are included here for convenience: + +For my database I’m going to use the [Sakila](https://dev.mysql.com/doc/sakila/en/sakila-introduction.html) sample database provided by MySQL. This database models a video rental store, including such aspects as customer information, staff info, film info, and actor info. The schema is as follows (schema taken from [here](https://dev.mysql.com/doc/sakila/en/sakila-structure.html)): + +![Sakila schema](/blog/connecting-to-a-mysql-database-part-2/sakila-schema.png) + +As you can see, this database includes much more than contact information, but our app will focus only on contact info. This is actually quite a typical scenario for a mobile app. I frequently create ad-hoc mobile apps that consume specific parts from the data source in order to help with testing of the main app. Mobile apps, in my experience, work quite well when they are focused on doing one task well, rather than doing a whole bunch of tasks as you would expect in a desktop application. + +So in this case, you can imagine that the store owners might want an app to help keep track of the contacts in the system. That is the app we will build here. + +### Installing the Database + +I’ll be using the mysql command-line client that is installed at /Applications/XAMPP/bin/mysql on my development machine. If yours is installed elsewhere then you’ll adjust your commands accordingly. + +First, download the Sakila database from [here](http://downloads.mysql.com/docs/sakila-db.tar.gz). (Link obtained from [this page](https://dev.mysql.com/doc/index-other.html) in case the direct link becomes broken later for some reason). + +When you extract the archive, you’ll find two SQL files: + + 1. sakila-schema.sql – This contains the database schema. + 2. sakila-data.sql – This contains the sample data + +We’ll install both into our database with the following commands. + + + $ mysql -u root -p < sakila-schema.sql + $ mysql -u root -p < sakila-data.sql + +Once these have executed, you should be able to log into mysql and see see the tables listed: + + + $mysql -u root -p + + + USE sakila; + Database changed + SHOW TABLES; + +----------------------------+ + | Tables_in_sakila | + +----------------------------+ + | actor | + | address | + | category | + | city | + | country | + | customer | + | customer_list | + | film | + | film_actor | + | film_category | + | film_list | + | film_text | + | inventory | + | language | + | nicer_but_slower_film_list | + | payment | + | rental | + | sales_by_film_category | + | sales_by_store | + | staff | + | staff_list | + | store | + +----------------------------+ + 22 rows in set (0.00 sec) + SELECT COUNT(*) FROM film; + +----------+ + | COUNT(*) | + +----------+ + | 1000 | + +----------+ + 1 row in set (0.02 sec) + SELECT COUNT(*) FROM film_text; + +----------+ + | COUNT(*) | + +----------+ + | 1000 | + +----------+ + 1 row in set (0.00 sec) + +## The Web Service + +I’m going to use Netbeans and its handy wizards to generate the web service this time around. Before we begin, we’ll need to set up NetBeans to connect to our MySQL database. + +### Configuring Netbeans to use MySQL + +Click on the “Services” tab, and right click on “Databases”: + +![Register mysql server](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-register-mysql-server.png) + +Select the “Register MySQL Server” option. This will bring up a setup dialog as follows. If you installed XAMPP, and are using the mysql server included with that, then your settings will look like mine. If not, you’ll need to customize them for your needs. + +![MySQL Settings](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-mysql-settings.png) + +After you have completed your settings, and clicked “OK”, you should see a new node appear under the “Databases” node named “MySQL Server at localhost:3306”. Expand this node to see all of your databases revealed. + +Right click on the “sakila” database, and select “Connect…​” as shown below: + +![Connect to MySQL database](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-mysql-connect.png) + +At this point we should have all of the groundwork covered to create our server project. + +### Creating the Web Service Project + +In Netbeans select “File” > “New Project…​”, then in the new project wizard select “Maven” > “Web Application”. + +__| I’m using Maven for this tutorial because I prefer it, but you could also use an ANT-based project under “Java Web” > “Web Application” and it should work fine. +---|--- + +![New project wizard](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-new-web-application-project.png) + +![New project wizard 2](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-new-web-application-project-2.png) + +After completing the new project wizard, you should see the SakilaRESTServer project in the project navigator, as shown here. + +![Web service project structure](/blog/connecting-to-a-mysql-database-part-2/sakila-project-structure-1.png) + +#### Generating the Web Services + +Currently the project is a generic web application without any web services or database access defined. Let’s add that now. + +Right click on the “SakilaRESTServer” project in the project explorer, and select “New” > “RESTful Web Services from Database” as shown below: + +![RESTful Web Services from Database menu item](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-restful-web-services-from-database-menu.png) + +In the dialog that appears, in the Data Source select list, select “New Data Source…​”. + +![New datasource](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-new-datasource.png) + +Enter “jdbc/sakila” as the JNDI name, and then select the JDBC connection string for the sakila database from the pull-down: + +![New JNDI datasource dialog](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-new-jndi-datasource-dialog.png) + +After clicking “OK”, you should see the “Available Tables” list populated as shown below. + +![Available tables](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-webservice-available-tables.png) + +For this application, you should uncheck the “Include related tables” checkbox as we only want the “Customer” table, and the Customer_list view to be included. If you were to leave this checked, then all kinds of other information would be included by default in the REST responses which we don’t want. + +Now add the “Customer” and “Customer_List” tables to the “Selected Tables” list and click “Next”. + +The next page we’ll leave default: + +![Page 2 of webservice wizard](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-webservice-wizard-page-2.png) + +And same with the next page. + +![Page 3 of webservice wizard](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-webservice-wizard-page-3.png) + +Finally, click the “Finish” button to let the magic begin. + +Once the dust has settled, your project structure should look something like the following: + +![Project structure with REST services](/blog/connecting-to-a-mysql-database-part-2/sakila-netbeans-project-structure-with-rest-services.png) + +A few things to notice here: + + 1. Entity classes for Customer and CustomerList have been generated in the com.codename1.demos.sakila package. + 2. Corresponding web service facades have been generated in the com.codename1.demos.sakila. These are the actual web services that will handle requests. + +Take the time to browse through the entity classes and services to get a feel for what is going on. It should be reasonably straight forward. + +### Specify the ID field in CustomerList + +Since Customer_List is a view, Netbeans doesn’t know which column is the “id”, so we’ll need to add that. If you open the CustomerList class, you’ll see a compile error because of this. + +![Compile error](/blog/connecting-to-a-mysql-database-part-2/sakila-customerlist-id-compile-error.png) + +You’ll need to add the `@Id` annotation to the “ID” field declaration. Netbeans will assist you with this if you expant the little light bulb icon in the left column of the error line. + +### A Look at the Web Service Facades + +At this point our web service is done, but before proceeding, let’s take a look at some of the source so that we get a sense of how the web service will work. + +The CustomerFacade class looks like: + + + package com.codename1.demos.sakilarestserver.service; + + // redacted imports + + + @Stateless + @Path("com.codename1.demos.sakilarestserver.customer") __**(1)** + public class CustomerFacadeREST extends AbstractFacade { + @PersistenceContext(unitName = "com.codename1.demos_SakilaRESTServer_war_1.0-SNAPSHOTPU") + private EntityManager em; + + public CustomerFacadeREST() { + super(Customer.class); + } + + @POST + @Override + @Consumes({"application/xml", "application/json"}) + public void create(Customer entity) { __**(2)** + super.create(entity); + } + + @PUT + @Path("{id}") + @Consumes({"application/xml", "application/json"}) + public void edit(@PathParam("id") Short id, Customer entity) { __**(3)** + super.edit(entity); + } + + @DELETE + @Path("{id}") + public void remove(@PathParam("id") Short id) { __**(4)** + super.remove(super.find(id)); + } + + @GET + @Path("{id}") + @Produces({"application/xml", "application/json"}) + public Customer find(@PathParam("id") Short id) { __**(5)** + return super.find(id); + } + + @GET + @Override + @Produces({"application/xml", "application/json"}) + public List findAll() { __**(6)** + return super.findAll(); + } + + @GET + @Path("{from}/{to}") + @Produces({"application/xml", "application/json"}) + public List findRange(@PathParam("from") Integer from, @PathParam("to") Integer to) { __**(7)** + return super.findRange(new int[]{from, to}); + } + + @GET + @Path("count") + @Produces("text/plain") + public String countREST() { __**(8)** + return String.valueOf(super.count()); + } + + @Override + protected EntityManager getEntityManager() { + return em; + } + + } + +__**1** | The relative URL to the web service. To access this web service, you would append this value to the end of the URL for the web app. In our case is the full URL to this webservice. +---|--- +__**2** | Endpoint to insert a new record into the customer table. This can be accessed by sending a POST request to the webservice URL with appropriate XML or JSON data. +__**3** | Endpoint to update an existing record. This can be accessed by sending a PUT request to `{webservice_url}/{customer_id}` with the appropriate XML or JSON data. For example, if we wanted to update the customer with customer_id=10 we would send our PUT request to `` +__**4** | Endpoint to delete a record. This can be accessed by sending a DELETE request to `{webservice_url}/{customer_id}`. +__**5** | Endpoint to find a record by ID. This can be accessed by sending a GET request to `{webservice_url}/{customer_id}`. By default the web service returns XML. You’ll need to add the header `Accept: application/json` to indicate that it should return JSON. +__**6** | Endpoint to return a list of all records in the customer table. This can be accessed by sending a GET request to the webservice URL. As with other GET requests, you should use the Accept HTTP header to indicate whether you want the result in XML or JSON. +__**7** | Endpoint to return a list of only rows in the specified range. Accessed with a GET request to `{webservice_url}/{from}/{to}`. E.g. to get only the first 3 records in the table, we would send a GET request to `` +__**8** | Endpoint to return the number of rows in the customer table. This can be accessed by sending a GET request to `{webservice_url}/count`. + +Full class can be seen [here](https://github.com/shannah/cn1-mysql-java-restful-demo/blob/master/SakilaRESTServer/src/main/java/com/codename1/demos/sakilarestserver/service/CustomerFacadeREST.java) + +### Running/Testing the Project + +In the project explorer, right click on the SakilaRESTServer project and select “Run”. This should automatically start the bundled GlassFish server, and deploy our app. + +If all wend well, it should open your web browser to the index page which says “Hello World!”. + +Next, we’ll test out the actual webservices. + +In the project explorer, uner the “RESTful Web Services” folder, you should see two web services listed. Right click on either of them and select “Test Resoure Uri” as shown here: + +![Testing resource uri](/blog/connecting-to-a-mysql-database-part-2/sakila-test-resource-uri.png) + +This should open up your web browser with an XML feed of all of the records in the customers table. + +## The Client App + +I’m changing very little of the Client app from the Xataface client version shown in my previous post. Instead of the [CN1Xataface library](https://github.com/shannah/cn1-xataface), which is designed to consume a [Xataface](http://xataface.com)-powered web-service, I’m using the GenericWebserviceClient.cn1lib which is designed to consume a generic web service, with APIs like the web service that we just created. This library should be applicable to a most of the APIs in production today. + +The [GenericWebserviceClient.cn1lib](https://github.com/shannah/cn1-generic-webservice-client) includes a `RESTfulWebServiceClient` class with the following main methods: + + + // Delete a record with id asynchronously + public void delete(String id, SuccessCallback callback); + + // Create a new record with the given data asynchronously + public void create(Map data, SuccessCallback callback); + + // Edit an existing record with given data asynchronously. + public void edit(String id, Map data, SuccessCallback callback); + + // Count the number of records provided by the web service. + public void count(SuccessCallback callback); + + // Find records provided by the web service + public void find(Query query, SuccessCallback callback) + +The `Query` class allows you to specify a find by record ID or on a range. It can be overridden to provide additional criteria to access other methods of a webservice API if they are required. + +You can view the source of the `RESTfulWebserviceClient` class [here](https://github.com/shannah/cn1-generic-webservice-client/blob/master/GenericWebserviceClient/src/com/codename1/ws/RESTfulWebServiceClient.java). + +The client App source is as follows (redacted for clarity): + + + package com.codename1.demos.sakila; + + // redacted imports ... + + import com.codename1.ws.RESTfulWebServiceClient; + import com.codename1.ws.RESTfulWebServiceClient.Query; + import com.codename1.ws.RESTfulWebServiceClient.RowSet; + + + /** + * This file was generated by Codename One for the purpose + * of building native mobile applications using Java. + */ + public class SakilaDemo { + + // redacted member variables ... + + String customerEndpoint = "http://localhost:8080/SakilaRESTServer/webresources/com.codename1.demos.sakilarestserver.customer"; __**(1)** + + // Database Connection Properties + RESTfulWebServiceClient client; + + + // redacted utility methods ... + + // Lifecycle Methods ------------------------------------------------------- + public void init(Object context) { + theme = UIManager.initFirstTheme("/theme"); + + // Enable Toolbar on all Forms by default + Toolbar.setGlobalToolbar(true); + + // Pro only feature, uncomment if you have a pro subscription + // Log.bindCrashProtection(true); + + client = new RESTfulWebServiceClient(customerEndpoint); __**(2)** + } + + public void start() { + if(current != null){ + current.show(); + return; + } + Form hi = new Form("Contacts"); + hi.setLayout(new BorderLayout()); + + hi.show(); + Display.getInstance().callSerially(()->{ + loadContacts(rowset->{ __**(3)** + + hi.addComponent(BorderLayout.CENTER, createContactsList(hi, rowset)); + }); + }); + } + + public void stop() { + // redacted ... + } + + + public void destroy() { + } + + // Web Service Methods ----------------------------------------------------- + + /** + * Loads all of the contacts from the database asynchronously. On complete + * the callback will be called with the resulting rowset as a parameter, or + * null if there was an error. + * @param callback Callback to handle the received rowset. + */ + private void loadContacts(SuccessCallback callback) { __**(4)** + Query q = new Query(); __**(5)** + client.find(q, callback); __**(6)** + + } + + /** + * Convert a record from the "contact" table into a Contact object. + * @param record A record from the "contact" table. + * @return A Contact object + */ + private static Contact createContact(Map m) { __**(7)** + Result record = Result.fromContent(m); + Contact c = new Contact(); + c.setFirstName(record.getAsString("firstName")); + c.setFamilyName(record.getAsString("lastName")); + c.setPrimaryEmail(record.getAsString("email")); + return c; + } + + /** + * Convert a rowset (from the contact table) into an array of Contact + * objects + * @param rowset A rowset from the contact table. + * @return An array of Contact records. + */ + private static Contact[] rowsetToContactsArray(RowSet rowset) { __**(8)** + List lst = new ArrayList(); + for (Map record : rowset) { + lst.add(createContact(record)); + } + return lst.toArray(new Contact[lst.size()]); + } + + // View Factory Methods ---------------------------------------------------- + + /** + * Creates a list of contacts included in the specified rowset. + * @param parentForm The parent form + * @param rowset The rowset to encapsulate (from the "contact" table) + * @return A container to be added to the form. + */ + private Container createContactsList(Form parentForm, RowSet rowset) { + Contact[] contacts = rowsetToContactsArray(rowset); + + // redacted image creation stuff... + + final Container contactsDemo = new Container(BoxLayout.y()); + contactsDemo.setScrollableY(true); + + for(Contact c : contacts) { + Container row = createContactRow(c, contactsDemo); + if (row != null) { + contactsDemo.add(row); + } + } + contactsDemo.revalidate(); + finishedLoading = true; + + RowSet[] lastSet = new RowSet[]{rowset}; + InfiniteScrollAdapter.createInfiniteScroll(contactsDemo, () -> { + Query nextQuery = lastSet[0].getNextQuery(); __**(9)** + if (nextQuery.getSkip() > lastSet[0].getSkip()) { + + client.find(nextQuery, newResult -> { __**(10)** + if (newResult == null) { + return; + } + List toAdd = new ArrayList(); + for (Map row : newResult) { + Container cntRow = createContactRow(createContact(row), contactsDemo); + if (cntRow != null) { + toAdd.add(cntRow); + } + } + InfiniteScrollAdapter.addMoreComponents(contactsDemo, toAdd.toArray(new Component[toAdd.size()]), true); + lastSet[0] = newResult; + contactsDemo.revalidate(); + }); + } + }); + + return contactsDemo; + } + + /** + * Creates a single row for the contact list that encapsulates the provided + * contact. + * @param c The contact to represent with this row. + * @param parent The parent container to which the row is to be added. This method doesn't actually add the + * row to the parent, but it does need to reference it for some of the listeners that are added to the row. The caller + * should add the resulting row to the parent after calling this method. + * @return A container encapsulating the row, or null if the contact didn't have a name. + */ + private Container createContactRow(Contact c, Container parent) { + // redacted same 'ol same 'ol + } + + } + +__**1** | The end point for the web service. We got this directly from the `@Path` annotation of the `CustomerFacadeREST` class on the server. +---|--- +__**2** | Instantiate a client for the web service. Notice that we passed the URL to the endpoint in the constructor. +__**3** | We call loadContacts() to asynchronously load the contacts inside the start() method. +__**4** | The implementation of `loadContacts()` which simply wraps a call to `RESTfulWebServiceClient.find()`. +__**5** | Create a new `Query` for the find request. By default a query is set to load the first 30 rows of the end point. +__**6** | We use the `find()` method to asynchronously load records from our end point. +__**7** | `createContact()` is a convenience method to convert our Maps of customer data received from the web service into `Contact` objects which our UI +was already set up to use. Note one difference from the Xataface version in the previous blog post is that the property names use camel-case instead of snake case. +__**8** | `rowsetToContactsArray` converts an entire RowSet received from the web service into an array of `Contact` records. +__**9** | We use the `InfiniteScrollAdapter` to progressively load more rows as required. `RowSet` includes a convenience `getNextQuery()` method to get query to produce the next page of results. +__**10** | Finally we load the next page of results inside the InfiniteScrollAdapter using `client.find()`. + +See the full source [here](https://github.com/shannah/cn1-mysql-java-restful-demo/blob/master/SakilaMobileApp/src/com/codename1/demos/sakila/SakilaDemo.java). + +## The Final Results + +This app is effectively identical to the one from our previous post, so it will look the same. + +![Contacts list](/blog/connecting-to-a-mysql-database-part-2/sakila-cn1-ipad-contacts-list.png) + +## Summary + +This brief tutorial demonstrated how you can set up a web service facade in front of a MySQL database to be consumed by a Codename One app. It introduced the GenericWebServiceClient library as tool to help you consume web services of this kind. This library should be applicable to the vast majority of RESTful APIs in production today, and it is easily extendible so you can customize it to suit your specific needs if they aren’t met out of the box. + +__| This post completely ignored security concerns. The examples here produced web services that are effectively open to the world. In a future post I may cover security, but for now, I leave it to you to make sure that you secure your web services. +---|--- + +Having demonstrated two different ways to develop essentially the same app, you may be wondering which approach is better. My response would be that it depends. Using Xataface in the back-end provides quite a bit of query flexibility in the client for free. However, the Java solution will perform better under load. Personally I use Xataface a lot for setting up administration tools and ad-hoc apps. If I plan to build a service that will scale to millions of users (thousands of requests per second), I will move towards the JVM. + +## Resources + + 1. [The GenericWebService.cn1lib Repo on Github](https://github.com/shannah/cn1-generic-webservice-client) + 2. [Github Repo for the projects in this tutorial](https://github.com/shannah/cn1-mysql-java-restful-demo) +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **thunderkilll** — April 24, 2018 at 9:10 am ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database-part-2.html#comment-23952)) + +> thank you for this i hope you can make a video of it so we can understand more +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database-part-2.html) + + +### **Chris B** — November 6, 2020 at 6:40 am ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database-part-2.html#comment-24366)) + +> Is this possible in eclipse? I’m trying to connect a Codename One application I have built in eclipse to an AWS RDS database I’ve built. Both Codename One and AWS are brand new to me, and I have no idea what I am doing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database-part-2.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/connecting-to-a-mysql-database.md b/docs/website/content/blog/connecting-to-a-mysql-database.md new file mode 100644 index 0000000000..4f161a7548 --- /dev/null +++ b/docs/website/content/blog/connecting-to-a-mysql-database.md @@ -0,0 +1,787 @@ +--- +title: Connecting to a MySQL Database from Codename One +slug: connecting-to-a-mysql-database +url: /blog/connecting-to-a-mysql-database/ +original_url: https://www.codenameone.com/blog/connecting-to-a-mysql-database.html +aliases: +- /blog/connecting-to-a-mysql-database.html +date: '2016-11-23' +author: Steve Hannah +--- + +![Header Image](/blog/connecting-to-a-mysql-database/connecting-mysql-to-codenameone.jpg) + +In the following series of blog posts I’m going to shift some attention to server-side development in so much as it can complement a Codename One client application. In this post I’ll demonstrate how you can combine a MySQL database, a web-service layer, and a Codename One client to produce a “Contacts” app. I’m going to steal the Contacts code from the Kitchen Sink demo for the UI, but I’ll implement a different datasource that loads the contacts from a remote MySQL database instead of from the phone’s internal contacts. + +## Requirements + +I’ll be using [Xataface](http://xataface.com) (which is built with PHP) for the web service, and MySQL for the database, so I’ll need to have a LAMP stack installed on my server with PHP 5 or higher, and MySQL 5 or higher. For development, I am going to use [XAMPP](https://www.apachefriends.org/index.html) because it provides everything with a simple installer – and it works on both Mac and Windows. If you’re on Linux, then it’s arguably easier – but I won’t cover it here. I’m using a Mac OS X development machine. + +__ | While I am using a PHP-based solution for the web service, this tutorial doesn’t require you to have any knowledge of PHP, and, in fact, doesn’t involve a single line of PHP code. +---|--- + +## The Database + +For my database I’m going to use the [Sakila](https://dev.mysql.com/doc/sakila/en/sakila-introduction.html) sample database provided by MySQL. This database models a video rental store, including such aspects as customer information, staff info, film info, and actor info. The schema is as follows (schema taken from [here](https://dev.mysql.com/doc/sakila/en/sakila-structure.html)): + +![Sakila schema](/blog/connecting-to-a-mysql-database/sakila-schema.png) + +As you can see, this database includes much more than contact information, but our app will focus only on contact info. This is actually quite a typical scenario for a mobile app. I frequently create ad-hoc mobile apps that consume specific parts from the data source in order to help with testing of the main app. Mobile apps, in my experience, work quite well when they are focused on doing one task well, rather than doing a whole bunch of tasks as you would expect in a desktop application. + +So in this case, you can imagine that the store owners might want an app to help keep track of the contacts in the system. That is the app we will build here. + +### Installing the Database + +I’ll be using the mysql command-line client that is installed at /Applications/XAMPP/bin/mysql on my development machine. If yours is installed elsewhere then you’ll adjust your commands accordingly. + +First, download the Sakila database from [here](http://downloads.mysql.com/docs/sakila-db.tar.gz). (Link obtained from [this page](https://dev.mysql.com/doc/index-other.html) in case the direct link becomes broken later for some reason). + +When you extract the archive, you’ll find two SQL files: + + 1. sakila-schema.sql – This contains the database schema. + + 2. sakila-data.sql – This contains the sample data + +We’ll install both into our database with the following commands. + + + $ mysql -u root -p < sakila-schema.sql + $ mysql -u root -p < sakila-data.sql + +Once these have executed, you should be able to log into mysql and see see the tables listed: + + + $mysql -u root -p + + + USE sakila; + Database changed + SHOW TABLES; + +----------------------------+ + | Tables_in_sakila | + +----------------------------+ + | actor | + | address | + | category | + | city | + | country | + | customer | + | customer_list | + | film | + | film_actor | + | film_category | + | film_list | + | film_text | + | inventory | + | language | + | nicer_but_slower_film_list | + | payment | + | rental | + | sales_by_film_category | + | sales_by_store | + | staff | + | staff_list | + | store | + +----------------------------+ + 22 rows in set (0.00 sec) + SELECT COUNT(*) FROM film; + +----------+ + | COUNT(*) | + +----------+ + | 1000 | + +----------+ + 1 row in set (0.02 sec) + SELECT COUNT(*) FROM film_text; + +----------+ + | COUNT(*) | + +----------+ + | 1000 | + +----------+ + 1 row in set (0.00 sec) + +## The Web Service + +For the web service layer, I’m going to use Xataface because it requires about the least amount of configuration necessary for us to connect to a MySQL data source over HTTP. + +DISCLAIMER: I am the creator of Xataface. I developed and released the original version in 2005, and have used it on countless apps since that time. It is useful setting up an administration interface for a MySQL database quickly. + +There are a few different ways to set up a Xataface application. The fastest, easiest way is using the [Xataface Yeoman generator](https://www.npmjs.com/package/generator-xataface). + +__ | You’ll need to have [NodeJS](https://nodejs.org/en/) and [Yeoman](http://yeoman.io/) installed on your development machine to use the Yeoman generator. Don’t worry, they will probably be the most painless installs you ever have to do. +---|--- + +### Setting up the Xataface App + +Open a command prompt and navigate to a web-accessible directory. In my case, I’m using XAMPP which stores the web documents in /Applications/XAMPP/htdocs, so that is where I will go: + + + $ cd /Applications/XAMPP/htdocs + +At the prompt type: + + + $ yo xataface sakila + +__ | If your `mysql` binary is not in your environment PATH you’ll need to provide it via that `--mysql` option. Similarly if git is not in your environment path you’ll need to provide the `--git` option. +---|--- + +The above command basically says “create a Xataface application in the directory named ‘sakila'”. + +Now, follow the prompts: + +First it will ask you for some database connection information. + + + ? MySQL Hostname localhost + ? App Database Name sakila + ? App Database Username sakila + ? App Database Password ******** + +In our case the database host is localhost, the database name is “sakila”, and we are going to generate a user for this application named “sakila” with password “password” that has full access to the “sakila” database. + +Next it will ask us which tables to include in the main menu. This is only used by the web interface for the app, which is beyond the scope of this tutorial. We are merely using Xataface as a thin web-service layer to enable our Codename One app to query the database. Nonetheless, we need to include at least one table here, so we’ll add the “customer” table to the main menu. + + + ? List the tables that should be included in the main menu in the form: table1=L + abel1,table2=Label2, etc... customer=Customers + +Next it will ask us about our authentication and permission preferences. Xataface provides a rich multi-user authentication and permissions system that will allow to decide exactly who can access what. This generator will setup the the default table-based authentication and add a “users” table to the database if you choose (and we will choose to do so). By default there are 3 levels of user accounts: + + 1. ADMIN + + 2. USER + + 3. (i.e. not logged in). + +By default, ADMIN users can access everything, regular users can access everything, but in a read-only fashion, and the public (i.e. not logged in) can access nothing. + + + Default settings authentication are as follows: + Table-based authentication with Users table definition: + create table if not exists `users` ( + `username` VARCHAR(100) NOT NULL PRIMARY KEY, + `password` VARCHAR(64) NOT NULL, + `role` ENUM('USER','ADMIN') DEFAULT 'USER', + `email` VARCHAR(255) NOT NULL, + UNIQUE KEY (`email`)); + + With sha1 encryption on the password field. + ADMIN users are granted ALL permissions, logged in users are granted READ ONLY permissions, and the public (i.e. not logged-in users) are granted NO ACCESS. + + ? Would you like to use these default authentication settings? Yes + +At this point it will create the “sakila” directory and set up some of the scaffold file structure for the application. + + + Cloning xataface into /Applications/XAMPP/xamppfiles/htdocs/sakila + Cloning into '/Applications/XAMPP/xamppfiles/htdocs/sakila/xataface'... + remote: Counting objects: 11025, done. + remote: Compressing objects: 100% (46/46), done. + remote: Total 11025 (delta 23), reused 0 (delta 0), pack-reused 10979 + Receiving objects: 100% (11025/11025), 16.87 MiB | 5.01 MiB/s, done. + Resolving deltas: 100% (6630/6630), done. + Checking connectivity... done. + Checking out files: 100% (2458/2458), done. + Copying .htaccess file + Copying .htaccess file to templates_c + +Now it will ask us about modifications that need to be made to the databse. + + + ? Create the database sakila now? No + ? Create the user sakila now? Yes + ? Grant permissions to sakila now? Yes + This generator needs to execute some SQL commands that require MySQL root permissions. This may include things like creating a database for the app, creating a MySQL user for the app to access the database or granting permissions to a MySQL user for the app to access the database. + This username will not be used by the app itself and will not be stored anywhere. It is just for the purpose of setting up the app initially. + + ? Root MySQL Username root + ? Create the table users now? Yes + +We told the generator to create a “users” table to store user accounts, but we haven’t added any user accounts yet. Next, the generator will allow us to enter a first “admin” account. + + + ? Insert Admin user in users table? Yes + ? Admin username admin + ? Admin password ******** + ? Admin Email Address [[email protected]](/cdn-cgi/l/email-protection) + +Now, after running some SQL commands, the application should be set up. + + + The app has been successfully created at /Applications/XAMPP/xamppfiles/htdocs/sakila + +To verify that the app was set up correctly, we’ll point our web browser to the application. In my case the application is located at + +If all went well you should see a login form similar to the image below: + +![Sakila Login Form](/blog/connecting-to-a-mysql-database/sakila-login.png) + +You should also verify that your admin user was set up correctly, but trying to log in on this form. You should see a list of customers: + +![Sakila customer list](/blog/connecting-to-a-mysql-database/sakila-web-list.png) + +## The Client App + +On the client side, I’m going to use the [CN1Xataface library](https://github.com/shannah/cn1-xataface) to connect to the Xataface-powered web service that we just set up. Here is a redacted program listing of the entire app: + + + package com.mycompany.myapp; + // ... redacted imports ... + import com.xataface.query.XFClient; + import com.xataface.query.XFQuery; + import com.xataface.query.XFRecord; + import com.xataface.query.XFRowSet; + + // ... redacted imports + /** + * This file was generated by Codename One for the purpose + * of building native mobile applications using Java. + */ + public class MySQLContactsDemo { + + private Form current; + private Resources theme; + + // redacted member declarations + + // Database Connection Properties + private XFClient client; + + // ... redacted Style utility methods + + // Lifecycle Methods ------------------------------------------------------- + public void init(Object context) { + + // redacted boilerplate init stuff ... + + client = new XFClient("http://localhost/sakila/index.php"); __**(1)** + + } + + public void start() { + if(current != null){ + current.show(); + return; + } + Form hi = new Form("Contacts"); + hi.setLayout(new BorderLayout()); + + hi.show(); + + // Wrap loading of contacts in callSerially so that it happens after the form + // is shown.... + Display.getInstance().callSerially(()->{ + loadContacts(rowset->{ __**(2)** + hi.addComponent(BorderLayout.CENTER, createContactsList(hi, rowset)); + }); + }); + } + + public void stop() { + // redacted boilerplate ... + } + + public void destroy() { + } + + // Web Service Methods ----------------------------------------------------- + + /** + * Loads all of the contacts from the database asynchronously. On complete + * the callback will be called with the resulting rowset as a parameter, or + * null if there was an error. + * @param callback Callback to handle the received rowset. + */ + private void loadContacts(SuccessCallback callback) { __**(3)** + XFQuery q = new XFQuery("customer") + .sort(XFQuery.SortOrder.ASCENDING, "last_name") + .select("first_name", "last_name", "email") + .findAll(); + client.find(q, callback); + } + + /** + * Convert a record from the "contact" table into a Contact object. + * @param record A record from the "contact" table. + * @return A Contact object + */ + private static Contact createContact(XFRecord record) { __**(4)** + Contact c = new Contact(); + c.setFirstName(record.getString("first_name")); + c.setFamilyName(record.getString("last_name")); + c.setPrimaryEmail(record.getString("email")); + return c; + } + + /** + * Convert a rowset (from the contact table) into an array of Contact + * objects + * @param rowset A rowset from the contact table. + * @return An array of Contact records. + */ + private static Contact[] rowsetToContactsArray(XFRowSet rowset) { __**(5)** + List lst = new ArrayList(); + for (XFRecord record : rowset) { + lst.add(createContact(record)); + } + return lst.toArray(new Contact[lst.size()]); + } + + // View Factory Methods ---------------------------------------------------- + + /** + * Creates a list of contacts included in the specified rowset. + * @param parentForm The parent form + * @param rowset The rowset to encapsulate (from the "contact" table) + * @return A container to be added to the form. + */ + private Container createContactsList(Form parentForm, XFRowSet rowset) { + Contact[] contacts = rowsetToContactsArray(rowset); + + // redacted image generation code ... + + // Create the parent container + final Container contactsDemo = new Container(BoxLayout.y()); + contactsDemo.setScrollableY(true); + + // Add all of the rows to the container + for(Contact c : contacts) { + Container row = createContactRow(c, contactsDemo); + if (row != null) { + contactsDemo.add(row); + } + } + contactsDemo.revalidate(); + finishedLoading = true; + + // XFClient won't load the whole set all at once because that would be a waste of + // network traffic. Default batch size is 30. We use InfiniteScrollAdapter + // to load more of the result set as the user scrolls down the list. + + // Store reference to the last loaded rowset. We can use this + // to obtain the "next" rowset, the next time the infinite scroll adapter + // is fired. + XFRowSet[] lastSet = new XFRowSet[]{rowset}; + InfiniteScrollAdapter.createInfiniteScroll(contactsDemo, () -> { + + // Check if we have have already loaded all of the records in the found set. + if (lastSet[0].getFound() > lastSet[0].getLast()) { + + // Use the previous rowset to get the query to obtain the next result set. + XFQuery nextQuery = lastSet[0].getQuery().getNextQuery(); __**(6)** + + // Pass the query to the client to load the next result set asynchronously + client.find(nextQuery, newResult -> { + if (newResult == null) { + return; + } + List toAdd = new ArrayList(); + for (XFRecord row : newResult) { + Container cntRow = createContactRow(createContact(row), contactsDemo); + if (cntRow != null) { + toAdd.add(cntRow); + } + } + InfiniteScrollAdapter.addMoreComponents(contactsDemo, toAdd.toArray(new Component[toAdd.size()]), newResult.getLast() < newResult.getFound()); + + // Make sure to store this new result set as lastSet so that the next time + // we load records we continue where we left off + lastSet[0] = newResult; + contactsDemo.revalidate(); + }); + } + }); + + return contactsDemo; + } + + /** + * Creates a single row for the contact list that encapsulates the provided + * contact. + * @param c The contact to represent with this row. + * @param parent The parent container to which the row is to be added. This method doesn't actually add the + * row to the parent, but it does need to reference it for some of the listeners that are added to the row. The caller + * should add the resulting row to the parent after calling this method. + * @return A container encapsulating the row, or null if the contact didn't have a name. + */ + private Container createContactRow(Contact c, Container parent) { + // redacted... no Database-specific code here. + } + + } + +__**1** | Initialize the client +---|--- +__**2** | Load the contacts from Xataface Asynchronously +__**3** | The method that loads the contacts. Simply wraps an XFQuery that is submitted to the client. +__**4** | Utility method to convert an XFRecord into a Contact object +__**5** | Utility method to convert XFRowSet into an array of Contact objects. +__**6** | Use the `getNextQuery()` method to easily load the next batch of records. + +If you run the app in the Codename One simulator, it will look something like this: + +![Contacts list](/blog/connecting-to-a-mysql-database/sakila-cn1-ipad-contacts-list.png) + +The full program listing can be found [here](https://github.com/shannah/cn1-mysql-demo/blob/master/src/com/mycompany/myapp/MySQLContactsDemo.java). + +In redacting non-database-related sections from this program listing, I’m hoping to highlight just how easy it is to integrate data from our MySQL database into our Codename One app. All database requests are handled by the `XFClient` class which includes your basic CRUD methods: + + + // Perform async query on db to retrieve rowset + public void find( + XFQuery query, + SuccessCallback callback + ); + + // Save record asynchronously + public void save( + XFRecord record, + SuccessCallback callback + ); + + + // Delete record asynchronously + public void delete( + XFRecord record, + SuccessCallback callback + ); + +In our app we created a new client inside the `init()` method: + + + client = new XFClient("http://localhost/sakila/index.php"); + +__ | We used the localhost address to the Xataface app, which will only work when we are running in the simulator on the same machine as the server. If you want to test on device, you’ll need to use an address that is reachable from the device. You should be able to check your computer’s network settings to see what your machine’s LAN address is (e.g. “192.0.0.8”, or “steves-imac.local”). And ultimately when you deploy your app to production, you’ll use the “real” server address that should be accessible over the entire internet. +---|--- + +### Authentication + +Notice that we didn’t include any username or password information in our client. The `XFClient` class does include `setUsername()` and `setPassword()` methods, but we’ve omitted them here to allow the end user to enter their own account. The first time we run our app, it will prompt the user with a login dialog: + +![Codename One login](/blog/connecting-to-a-mysql-database/sakila-cn1-login.png) + +The nice thing about allowing the user to log in, is it allows you to customize the permissions on a per-user basis on the server side. For my demo, I only created a single ADMIN account, but you are also able to add more limited accounts that only have access to certain tables, fields, or rows from certain tables. + +### Building the Queries + +Database queries are encapsulated by the `XFQuery` class. Queries are always targeted on a single table. You can provide many types of filters on the results including, but not limited to: + + 1. Exact matches + + 2. Partial matches + + 3. Range matches (less than, greater than, less than or equal, greater than or equal, or in a range) + + 4. Full-text, multi-column matches. + +In our app the query that we used was: + + + XFQuery q = new XFQuery("customer") __**(1)** + .sort(XFQuery.SortOrder.ASCENDING, "last_name") __**(2)** + .select("first_name", "last_name", "email") __**(3)** + .findAll(); __**(4)** + client.find(q, callback); + +__**1** | Specifies query on the customer table +---|--- +__**2** | Sort results ascending by last name. +__**3** | Include only the first_name, last_name, and email fields in the results. +__**4** | Find all matches (as opposed to `findOne()` which will only fetch the first match. + +If we omit the `select()` call, it will just include all of the columns of the table in our result set. But this is a waste of bandwidth since we only need those 3 fields. It is also worth noting that we are only sorting on one column (last_name) here but we could chain multiple `sort()` calls into the query in order to sort on multiple fields. + +Let’s take a look at a few examples of how we could customize our query to get different results: + +**Filter on last_name** + +Only include results with last name “Smith” + + + q.matches("last_name", "Smith"); + +This would match “Smith” but not “Smithers” + +If you want to match “Smith” or “Smithers” we could do: + + + q.contains("last_name", "Smith"); + +This would match “Smith”, “Smithers”, or “Sexsmith”. If we wanted to exclude “Sexsmith” we could do something like: + + + q.like("last_name", "Smith%"); + +Or something a little more commonly practical, if we wanted only those contacts whose last name begins with “S”: + + + q.like("last_name", "S%"); + +__ | We could achieve the same effect with `q.in("S", "SZZZZZZ")` +---|--- + +**Filter on Dates** + +Suppose we were only interested in customers that had been modified in the past day: + + + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DATE, -1); + q.greaterThan("modified", cal.getTime()); + +Xataface supports many querying features not listed here. For more detailed information see the cn1-xataface docs. + +### Using MySQL Views + +One limitation of the XFQuery class is that queries are always only performed on a single table. What if you need to perform a more complex query that spans across multiple tables, as is a common requirement of datbase applications. The easiest solution is to create a view in your database that contains all of the data you need, and then query that. For example, in our application we used the customer table which included only the customer name and email address. However, the database stores quite a bit of information about the customer in other tables. Of interest are the customer’s address and phone number for an app like this, and the database designers provided a nice view that includes all of this information: + + + CREATE VIEW `customer_list` AS select + `cu`.`customer_id` AS `ID`, + concat(`cu`.`first_name`,_utf8' ',`cu`.`last_name`) AS `name`, + `a`.`address` AS `address`, + `a`.`postal_code` AS `zip code`, + `a`.`phone` AS `phone`, + `city`.`city` AS `city`, + `country`.`country` AS `country`, + if(`cu`.`active`,_utf8'active',_utf8'') AS `notes`, + `cu`.`store_id` AS `SID` + from (( + (`customer` `cu` + join `address` `a` on((`cu`.`address_id` = `a`.`address_id`))) + join `city` on((`a`.`city_id` = `city`.`city_id`))) + join `country` on((`city`.`country_id` = `country`.`country_id`) + )) + +Xataface will allow you to query a view just as if it were a regular table, except that you need to add a tiny bit of configuration to let it know what the primary key of the view is. + +Just to get you started down this path, let’s open the terminal and navigate to the `sakila` directory that we created for our app: + + + $ cd /Applications/XAMPP/htdocs/sakila + +Now we’ll create a “fields.ini” file for the “customer_list” table (er view) at `tables/customer_list/fields.ini`. + + + $ mkdir tables/customer_list + $ touch tables/customer_list/fields.ini + +And inside the fields.ini file we place: + + + [ID] + Key=PRI + +This configuration marks the ID field as the primary key of the customer_list view. + +Now we can use the customer_list view from our Codename One app as if it were a regular table. + +## Try out the App + +For your convenience, I have published the app on a development server so that you can try it out yourself. I have removed the “admin” user and added a read-only account. You should log in with: + +Username: demo, Password: demo (case sensitive) + + 1. [Xataface Admin Back-end](http://sakila-demo.weblite.ca) + + 2. [Contacts Demo](http://sakila-demo.weblite.ca:8080/MySQLContactsDemo/) (The Codename One app built using the Javascript port). + + 3. [Download the .war file](http://sakila-demo.weblite.ca/MySQLContactsDemo.war) of the JS version and install/run it in your own servlet container. + + 4. [Download APK for Android](http://sakila-demo.weblite.ca/MySQLContactsDemo.apk) + +## Resources + + 1. [The CN1Xataface cn1lib](https://github.com/shannah/cn1-xataface) + + 2. [The Full Source Code of the server-side portion of this tutorial](https://github.com/shannah/sakila) + + 3. [The Full Source of the client app portion of this tutorial](https://github.com/shannah/cn1-mysql-demo) + + 4. [The Xataface Website](http://xataface.com) +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Toby Mundy** — December 1, 2016 at 10:02 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-24243)) + +> I followed the tutorial but could not get the server setup properly. All appeared to go well but when I pointed the web browser at to test the server setup I just got the following error in the browser: +> +> Warning: mysqli_connect(): (HY000/1045): Access denied for user ‘sakila’@’localhost’ (using password: YES) in C:xampphtdocssakilaxatafacexfdbdriversmysqli.php on line 4 +> +> Warning: mysqli_error() expects exactly 1 parameter, 0 given in C:xampphtdocssakilaxatafacexfdbdriversmysqli.php on line 17 +> +> Fatal error: Uncaught exception ‘Exception’ with message ‘Error connecting to the database: ‘ in C:xampphtdocssakilaxatafaceDatafaceApplication.php:608 Stack trace: #0 C:xampphtdocssakilaxatafaceDatafaceApplication.php(1081): Dataface_Application->Dataface_Application(NULL) #1 C:xampphtdocssakilaxatafacepublic-api.php(58): Dataface_Application::getInstance(NULL) #2 C:xampphtdocssakilaindex.php(4): df_init(‘C:\xampp\htdocs…’, ‘xataface’) #3 {main} thrown in C:xampphtdocssakilaxatafaceDatafaceApplication.php on line 608 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **shannah78** — December 2, 2016 at 4:23 am ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-23230)) + +> It appears that the database user wasn’t created properly. Check the conf.db.ini file. It should list the username and password that it is trying to connect with. Then ensure that mysql has that user. +> +> If you need to add the user “username” with password “password” in mysql you can do it with: +> +> create user ‘username’@localhost identied by ‘password’; +> grant all privileges to on sakila.* to username@localhost; +> flush privileges; +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **Toby Mundy** — December 2, 2016 at 1:11 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-22821)) + +> Thanks, I had not added mysql to environment PATH. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **Rudy Lemaitre** — February 8, 2017 at 3:18 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-21562)) + +> Hi all, +> i have juste a question for the lib. +> I have copy / past the lib cn1-xtaface.cn1lib in my lib folder in eclipse project, i build the path. +> After i create importe the lib and create the private XFClient client, but eclipse note know the lib and methode. +> Can you help me ? +> thanks for your help +> +> sorry for my english +> +> thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **shannah78** — February 8, 2017 at 4:43 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-23147)) + +> Did you refresh cn1libs in your project after adding the cn1-xataface.cn1lib? Note: You can also install it via Codename One settings (in extensions). But you’d still need to to the refresh cn1libs step after that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **Rudy Lemaitre** — February 8, 2017 at 6:14 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-22992)) + +> Rudy Lemaitre says: +> +> Hi restart Eclipse, it’s the same ? +> I try refresh tomorrow, thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **Rudy Lemaitre** — February 9, 2017 at 8:30 am ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-24125)) + +> Rudy Lemaitre says: +> +> hello, +> i refresh but it’s the same [https://uploads.disquscdn.c…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **Rudy Lemaitre** — February 9, 2017 at 10:44 am ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-23167)) + +> Rudy Lemaitre says: +> +> it”s ok now +> i make a new install of eclispe and works now 🙂 +> thanks 😉 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **Chris** — April 10, 2017 at 8:10 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-21570)) + +> Chris says: +> +> I’m new to this – do I need to install Xataface on my web server, or just as part of the app? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **shannah78** — April 11, 2017 at 3:58 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-23222)) + +> shannah78 says: +> +> Xataface goes on your web server. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **Chris** — April 11, 2017 at 4:09 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-23108)) + +> Chris says: +> +> Thanks – I use webspace from x10hosting, so presumably I can’t install Xataface on there? Or is it possible to do it when you are renting webspace? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **shannah78** — April 12, 2017 at 4:40 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-23131)) + +> shannah78 says: +> +> Yes. You can use Xataface on any host that has PHP and MySQL. The instructions in this article assume you have your own server (or have shell access and server has npm installed). But you can also just upload xataface manually to your webspace. Here are some manual install instructions: [http://xataface.com/wiki/Ho…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **Brutus** — April 27, 2017 at 1:17 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-23339)) + +> Brutus says: +> +> Hi steve can you please also give an example of how to upload a file thanks! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **Shai Almog** — April 28, 2017 at 5:24 am ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-23132)) + +> Shai Almog says: +> +> [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **Pawan Jain** — September 13, 2020 at 8:01 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-24338)) + +> [Pawan Jain](https://lh4.googleusercontent.com/-0r85m23OrDM/AAAAAAAAAAI/AAAAAAAAAAA/AMZuucnCeH5OcGgKnuB6aIIm5xdVdmFh3Q/photo.jpg) says: +> +> Hi, +> +> I am trying to create this project. I have successfully created and configured on server side and able to login and connect to Sakila database and fetch customers. +> However, I am facing issues when trying to set up codename one client in Eclipse (Oxygen). I have set up the project correctly, and also copied the cn1-xataface.cn1lib in lib folder and refreshed lib. I still continue to see errors – the following import statements continue to fail: +> import com.xataface.query.XFClient; +> import com.xataface.query.XFQuery; +> import com.xataface.query.XFRecord; +> import com.xataface.query.XFRowSet; +> +> Also tried reboot my PC but still the same issue. +> My codename one setup is correct that I can create simple demo Apps and run. +> +> Any suggestions please? +> +> Thanks, Pawan +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + + +### **Steve Hannah** — September 16, 2020 at 9:52 pm ([permalink](https://www.codenameone.com/blog/connecting-to-a-mysql-database.html#comment-24340)) + +> [Steve Hannah](https://lh3.googleusercontent.com/a-/AAuE7mBmUCgKSZtJ2cqeHgj6bdPY2AAQ10roHlMpgRWc) says: +> +> It sounds like it is having issues refreshing the xataface cn1lib. Try again, going through the cycle of “Codename One” > “Refresh Cn1libs”. Then a clean build. Check the “lib/impl/cls” directory (which is where the cn1lib classes get extracted to when they are installed), and ensure that the specified classes are there. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fconnecting-to-a-mysql-database.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/continuous-integration.md b/docs/website/content/blog/continuous-integration.md new file mode 100644 index 0000000000..a473254dd0 --- /dev/null +++ b/docs/website/content/blog/continuous-integration.md @@ -0,0 +1,83 @@ +--- +title: Continuous Integration +slug: continuous-integration +url: /blog/continuous-integration/ +original_url: https://www.codenameone.com/blog/continuous-integration.html +aliases: +- /blog/continuous-integration.html +date: '2014-12-07' +author: Shai Almog +--- + +![Header Image](/blog/continuous-integration/continuous-integration-1.png) + + + + + +![Picture](/blog/continuous-integration/continuous-integration-1.png) + + + + + + + +Building enterprise mobile apps can be pretty challenging especially when dealing with rapid changes, prototyping and corporate development requirements. + +One of the tools that has really revolutionized this field is Jenkins and related CI tools that allow developers to instantly track failures back to a specific revision of their code commits with respect to QA work. + +Codename One was essentially built for continuous integration since our build servers are effectively a building block for such an architecture. However, there are several problems with that the first of which is the limitation of server builds. If all users would start sending builds with every commit our servers would instantly become unusable due to the heavy load. To circumvent this we are now introducing CI support but only on the Enterprise level which allows us to stock more servers to cope with the rise in demand related to the feature. + +To integrate with any CI solution just use our standard Ant targets such as + + + + + +build-for-android-device + + +, build-for-iphone-device etc. Normally, this would be a problem since the build is sent but since it isn’t blocking you wouldn’t get the build result and wouldn’t be able to determine if the build passed or failed. To enable this just edit the build XML and add the attribute automated=”true” to the codeNameOne tag in the appropriate targets. This will deliver a result.zip file under the dist folder containing the binaries of a successful build. It will also block until the build is completed. This should be pretty easy to integrate with any CI system together with our +[ +automated testing solutions +](http://www.codenameone.com/blog/test-it) +. + +This is just a first piece in what would hopefully be a larger piece of the puzzle e.g. running the automated tests on cloud devices using one of the device hosting services available. We will address those pieces based on demand/requirements from our enterprise users. + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — December 8, 2014 at 3:40 pm ([permalink](https://www.codenameone.com/blog/continuous-integration.html#comment-22236)) + +> Anonymous says: +> +> Thanks, this is a great addition to Codename One, any chances it will have some basic support to Pro users ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcontinuous-integration.html) + + +### **Anonymous** — December 9, 2014 at 11:52 am ([permalink](https://www.codenameone.com/blog/continuous-integration.html#comment-24241)) + +> Anonymous says: +> +> That is unlikely, too much server load. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcontinuous-integration.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/contribute-to-codename-one-during-hacktoberfest.md b/docs/website/content/blog/contribute-to-codename-one-during-hacktoberfest.md new file mode 100644 index 0000000000..cb065e8377 --- /dev/null +++ b/docs/website/content/blog/contribute-to-codename-one-during-hacktoberfest.md @@ -0,0 +1,82 @@ +--- +title: Contribute to Codename One during Hacktoberfest +slug: contribute-to-codename-one-during-hacktoberfest +url: /blog/contribute-to-codename-one-during-hacktoberfest/ +original_url: https://www.codenameone.com/blog/contribute-to-codename-one-during-hacktoberfest.html +aliases: +- /blog/contribute-to-codename-one-during-hacktoberfest.html +date: '2021-10-01' +description: It’s Hacktoberfest time! 🎃 Contribute to Codename One for Hacktoberfest + to give back to open-source this October. +--- + +It’s Hacktoberfest time! 🎃 Contribute to Codename One for Hacktoberfest to give back to open-source this October. + +![Codename One - Hacktoberfest 2021](/blog/contribute-to-codename-one-during-hacktoberfest/Hacktoberfest-2021-1024x536.jpg) + +We’re excited that Codename One is participating in Hacktoberfest this year. Now in its eighth year, Hacktoberfest is a global online festival aiming to drive contribution and involvement in open source projects. + +We encourage contributions from the Hacktoberfest community. People of all backgrounds and skill levels are welcome! + +### What is Hacktoberfest? + +Hacktoberfest is a month-long global celebration of open source software run by DigitalOcean with a strong focus on encouraging contributions to open source projects. + +From senior developers to students learning to code; open source enthusiasts of all skill levels can participate. + +The rules are simple: create a minimum of 4 quality Pull Requests on GitHub to any open source project repo during the whole month of October and have them accepted by a maintainer. + +By completing this challenge, you will earn your Hacktoberfest 👕 swag or help plant a 🌲 tree. Just make sure to [register](https://hacktoberfest.digitalocean.com/register) first! + +👉 Learn more about Hacktoberfest [here](https://hacktoberfest.digitalocean.com/). + +### Why Contribute to Codename One? + +## History + +Codename One is a revolutionary mobile development solution started by ex-Sun Microsystems developers based on work that started within Sun. Codename One delivers the Write Once Run Anywhere (WORA) promise of Java for mobile devices by intelligently cross compiling to native code. + +## Established & Mature + +Codename One version 1.0 was released in 2012. It was the first solution to build native iPhone apps in Java and is still the most mature, performant and stable cross-platform mobile toolkit on the market. + +It is now being used by many well-known organizations including banks, government agencies and startups. + +## Free & Open Source + +The core of Codename One is free and open source. GPL + CE licensed so it is free to use with commercial projects. + +## Community + +Codename One has a consolidated and active community of developers and enthusiasts. + +If you are a true believer in Java and the power of cross-platform, you can help make Codename One even better! 🙌 + +### How to Contribute to Codename One? + +Before you start working on something, we would suggest talking to us in the [cn1 subreddit](https://www.reddit.com/r/cn1/) or asking a question on [stack overflow with the codenameone tag](http://stackoverflow.com/tags/codenameone). You can also contact us via the chat widget on our website. + +To make it easier to start contributing to Codename One, we’ve outlined some guidelines in our [CONTRIBUTING.md](https://github.com/codenameone/CodenameOne/blob/master/CONTRIBUTING.md) file available at our GitHub repository. + +## Steps to Contribute: + +• Visit [Hacktoberfest](https://hacktoberfest.digitalocean.com/) website and sign in with your GitHub account ✅ + +• Choose your favorite [Codename One issue](https://github.com/codenameone/CodenameOne/labels/Hacktoberfest) and submit your Pull Request 👨‍💻 + +• Wait for your PR to be reviewed and merged 💕 + +## Note + +> To make issues easier to discover, we have tagged them with relevant labels 🏷️ i.e. [Hacktoberfest](https://github.com/codenameone/CodenameOne/labels/Hacktoberfest), [good first issue](https://github.com/codenameone/CodenameOne/labels/good%20first%20issue) +> etc. + +Best of luck and Happy Hacktoberfest! 🎃 + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/cool-text-effects-mobile-app-phone-ios-android.md b/docs/website/content/blog/cool-text-effects-mobile-app-phone-ios-android.md new file mode 100644 index 0000000000..b217370d79 --- /dev/null +++ b/docs/website/content/blog/cool-text-effects-mobile-app-phone-ios-android.md @@ -0,0 +1,182 @@ +--- +title: Cool Text Effects for Your Mobile App on iPhone (iOS), Android etc. +slug: cool-text-effects-mobile-app-phone-ios-android +url: /blog/cool-text-effects-mobile-app-phone-ios-android/ +original_url: https://www.codenameone.com/blog/cool-text-effects-mobile-app-phone-ios-android.html +aliases: +- /blog/cool-text-effects-mobile-app-phone-ios-android.html +date: '2016-11-09' +author: Steve Hannah +--- + +![Header Image](/blog/cool-text-effects-mobile-app-phone-ios-android/cool-text-transformations.jpg) + +FontBox is a mature java library for loading, manipulating, and rendering fonts in Java. It gives you direct access to the font glyphs so that you can perform effects or transformations on them. A couple of years ago, I ported FontBox to Codename One, but since CN1 didn’t yet include support for drawing shapes, I made it dependent upon the [CN1Pisces library](https://github.com/shannah/CN1Pisces), which did support drawing shapes. This was cool but it had some major limitations; the main one being that FontBox fonts could only be used to draw strings on Pisces graphics contexts, which can only be rendered to an image – not directly to the screen. This meant that you couldn’t **just** use a FontBox font in your app (e.g. in a label or a button). You could only use it to write on an image. + +Fast forward to the present day, when Codename One supports [drawing shapes](https://www.codenameone.com/javadoc/com/codename1/ui/geom/GeneralPath.html) “natively” on all major platforms, I felt is was time to revamp this library so that it integrates better with Codename One. My goal was to be able to use a FontBox font interchangeably with “normal” fonts. E.g. for a label, button, text field, graphics context, etc…​ The motivation for this update came as I was developing the “Meme Maker” demo. I needed to draw some text that was filled white but had a black outline. Built-in fonts don’t have this ability, but since FontBox provides direct access to the font glyphs as paths (i.e. lines and curves) I could fairly easily create a font that had both fill and stroke. That’s just what I did, with the new `TTFFont` class. + +### What can `TTFFont` do that `Font` cannot? + +`TTFFont` is a subclass of `CustomFont` which is itself a subclass of `com.codename1.ui.Font`. Therefore it can be used in any place that a standard font is used. Why would you do this? + +TTFFont supports stroking, filling, or both, with different colors. E.g. You can create a font that is stroked with white, but filled with black. And you can specify the width of the stroke just as you would a normal shape. + +![Stroked and filled text](/blog/cool-text-effects-mobile-app-phone-ios-android/fontbox-text-normal.png) + +Figure 1. Stroked and filled text + +TTFFont supports both horizontal and vertical scaling, so you can make your text really skinny, or really wide, depending on what your requirements are. This also enables you to size text to fit a space **exactly**. + +![Stretched text](/blog/cool-text-effects-mobile-app-phone-ios-android/fontbox-text-stretched.png) + +Figure 2. Stretched text + +![Compressed text](/blog/cool-text-effects-mobile-app-phone-ios-android/fontbox-text-compressed.png) + +Figure 3. Compressed text + +`TTFFont` can load a TTF file from storage, file system, resources, or just from a plain old InputStream. This means that you can load fonts dynamically over a network if you want. + +### Drawbacks + +Since `TTFFonts` are actually rendered in CN1 as shapes, they will be slower than built-in fonts, which are rendered natively by the platform. Therefore, you should only use TTFFont in cases where you require its extra capabilities. That said, there was no noticeable “lag” introduced in the [Meme Maker app](https://github.com/shannah/mememaker) by my use of TTFFont. + +### Usage Examples + +#### Loading TTF File + +**From InputStream:** + + + TTFFont font = TTFFont.createFont("MyFont", inputStream); + +**From Resources:** + + + TTFFont font = TTFFont.createFont("MyFont", "/MyFont.ttf"); + +**From Storage/URL:** + + + TTFFont font = TTFFont.createFontToStorage("MyFont", + "font_MyFont.ttf", + "http://example.com/MyFont.ttf" + ); + +**From File System/URL:** + + + TTFFont font = TTFFont.createFontToFileSystem("MyFont", + FileSystemStorage.getInstance().getAppHomePath()+"/fonts/MyFont.ttf", + "http://example.com/MyFont.ttf" + ); + +**From Cache:** + + + TTFFont font = TTFFont.getFont("MyFont", 12); + +#### Setting Font for Style + + + myLabel.getAllStyles().setFont(font); + +#### Getting Particular Size Font + + + font = font.deriveFont(24); // get size 24 font. + +#### Horizontal and Vertical Scaling + + + font = font.deriveScaled(0.5f, 1.5f); + // scaled 50% horizontal, and 150% vertical + + font = font.deriveHorizontalScaled(0.5f); // scaled 50% horizontally + + font = font.deriveVerticalScaled(0.5f); // scaled 50% vertically + +#### Stroking and Filling + + + font = font.deriveStroked(Stroke(1f, Stroke.CAP_BUTT, Stroke.JOIN_MITER, 1f), #ff0000); + // Stroke with red 1px outline + + font = font.deriveStroked(Stroke(1f, Stroke.CAP_BUTT, Stroke.JOIN_MITER, 1f), null); + // Stroked - stroke color determined by graphics context's current color.. e.g. defers to Style's foreground color + + font = font.deriveStroked(null, 0x0); + // Not stroked + + font = font.deriveFilled(true, null); + // Filled - fill color determined by graphics context's current color.. e.g. defers to Style's foreground color + + font = font.deriveFilled(true, 0x00ff00); + // Filled with green + + font = font.deriveFilled(false, null); + // Not filled + +#### Antialias + + + font = font.deriveAntialias(true); + // Should be rendered antialiased + + font = font.deriveAntialias(false); + // should be rendered without antialias. + +#### Drawing Directly on Graphics Context + + + font.drawString(g, "Hello world", x, y); + + // Or ... + g.setFont(font); + g.drawString("Hello world", x, y); + +#### Appending to existing GeneralPath + + + font.draw(path, "Hello world", x, y, 1f /*opacity*/); + +### More About CN1FontBox + +For more information about CN1FontBox, check out the [CN1FontBox github repository](https://github.com/shannah/CN1FontBox). The best way to install it is through the “Extensions” section of the Codename One Settings for your project. + +### Get the Meme Maker App + + 1. [On the Play Store](https://play.google.com/store/apps/details?id=com.codename1.demos.mememaker) + + 2. [In the Windows Store](https://www.microsoft.com/en-us/store/p/codename-one-meme-maker/9nblggh441nf) + + 3. [In the iTunes Store](https://itunes.apple.com/us/app/codename-one-meme-maker/id1171538632) + + 4. [On GitHub](https://github.com/shannah/mememaker) +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — November 10, 2016 at 7:41 pm ([permalink](https://www.codenameone.com/blog/cool-text-effects-mobile-app-phone-ios-android.html#comment-22931)) + +> That’s very cool. Thanks once again for all your great work on CN1. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcool-text-effects-mobile-app-phone-ios-android.html) + + +### **Chibuike Mba** — November 11, 2016 at 9:09 am ([permalink](https://www.codenameone.com/blog/cool-text-effects-mobile-app-phone-ios-android.html#comment-21507)) + +> Nice one Steve. Thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcool-text-effects-mobile-app-phone-ios-android.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/corporate-guide.md b/docs/website/content/blog/corporate-guide.md new file mode 100644 index 0000000000..b655394692 --- /dev/null +++ b/docs/website/content/blog/corporate-guide.md @@ -0,0 +1,66 @@ +--- +title: Corporate Guide +slug: corporate-guide +url: /blog/corporate-guide/ +original_url: https://www.codenameone.com/blog/corporate-guide.html +aliases: +- /blog/corporate-guide.html +date: '2014-03-04' +author: Shai Almog +--- + +![Header Image](/blog/corporate-guide/corporate-guide-1.png) + + + + + +![Picture](/blog/corporate-guide/corporate-guide-1.png) + + + + +We recently introduced the corporate server option which is seeing initial deployments right now. As part of that we are now publishing the install guide to the general public, if you are considering the option of purchasing a corporate server but aren’t sure about the process of install you can follow the instructions +[ +here +](/corporate-server.html) +. + + + +In other news you might recall in a recent blog post I mentioned + +[ +we added isDragRegion +](http://www.codenameone.com/3/post/2014/02/wheel-drag.html) +, well its now deprecated in favor of a more ambitious getDragRegionStatus which can return multiple constants to help us fine tune the drag behavior to all the various edge cases and make the UI feel more responsive. + + + + +Up until now desktop applications in Codename One shared the same .cn1 storage as the simulator, this was a problem with multiple apps installed. Starting with current builds desktop apps should store their data under .AppMainClassName within the home directory. We also fixed the icon on the windows builds to appear correctly within the frame and the running apps menu (alt-tab etc.). + + + + + + +The Google Play ads were causing some issues in Gingerbread devices where clicks would have no effect, unfortunately we aren’t clear on why exactly this happens but its related to obfuscation probably removing some compatibility code needed by Google. The only workaround we found for this to work on older devices is to disable obfuscation on Android by using the build argument: android.enableProguard=false + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/course-updates.md b/docs/website/content/blog/course-updates.md new file mode 100644 index 0000000000..8d4462bb7d --- /dev/null +++ b/docs/website/content/blog/course-updates.md @@ -0,0 +1,64 @@ +--- +title: Course Updates +slug: course-updates +url: /blog/course-updates/ +original_url: https://www.codenameone.com/blog/course-updates.html +aliases: +- /blog/course-updates.html +date: '2017-07-24' +author: Shai Almog +--- + +![Header Image](/blog/course-updates/build-real-world-full-stack-mobile-apps-in-java.jpg) + +I hoped to finish migrating all of the material from the original bootcamp to the [new courses](https://codenameone.teachable.com/) but got delayed due to external influences. There isn’t much left so I’m sure I’ll be done with the existing modules in early August and get started on the first of the new modules. + +If you haven’t kept up I added a lot of modules over the past few weeks covering a very wide set of subjects such as animations, tablet support, cloud server setup and much more. + +One of the big additions to the [Deep Dive into Mobile Development with Codename One](https://codenameone.teachable.com/p/deep-dive-into-mobile-development-with-codename-one) is a new segment from Chidi Okwudire who is the author of [parse4cn1](https://github.com/sidiabale/parse4cn1) and the perfect person to teach it…​ This segment covers parse from the level of “I don’t know what parse is” to the level of adapting the app to the cloud server which is pretty cool! + +### Next in Line + +Now that this is coming to an end we need to start picking up the important modules you feel are missing in the academy. + +One thing I know we need to produce is a GUI builder tutorial, Steve has actually built a great one that we’ll publish soon in the blog but I think we need more than that although I’m not sure if these should be done now or later. + +What’s missing or isn’t covered enough? + +How can this be improved? + +Please let me know in the comments, I’ll use that and some of the other feedback I got and hopefully create a survey if necessary. + +Thanks! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Michael Lindvall** — July 25, 2017 at 2:20 pm ([permalink](https://www.codenameone.com/blog/course-updates.html#comment-23470)) + +> Michael Lindvall says: +> +> I thought the additional module for parse4cn1 was a great addition to the training. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcourse-updates.html) + + +### **Shai Almog** — August 9, 2017 at 8:04 am ([permalink](https://www.codenameone.com/blog/course-updates.html#comment-23720)) + +> Shai Almog says: +> +> I would create new content with the GUI builder. There is no reason to redo things I already covered. +> GUI builder content takes longer to create as everything needs to be done via video and editing. The GUI builder is still evolving so it’s unclear when I’ll get to it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcourse-updates.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/crashing.md b/docs/website/content/blog/crashing.md new file mode 100644 index 0000000000..e7a9d6a9a3 --- /dev/null +++ b/docs/website/content/blog/crashing.md @@ -0,0 +1,49 @@ +--- +title: Crashing +slug: crashing +url: /blog/crashing/ +original_url: https://www.codenameone.com/blog/crashing.html +aliases: +- /blog/crashing.html +date: '2013-07-16' +author: Shai Almog +--- + +![Header Image](/blog/crashing/crashing-1.png) + + + + + +![Picture](/blog/crashing/crashing-1.png) + + + + +** +Note: +** +we decided to go in a different direction than the content of this blog post. We will make a new post with further details when we complete the new feature. Generally we found a way to allow deobfuscation of release binaries as well so you would be able to get a crash report on standard applications. + + + + + + +In an ideal world your app would work perfectly on the device just as it does on the simulator, however that ideal world never exists under any development environment. Performance is different and unfortunately you occasionally get crashes on the device that you don’t get on a simulator. The reasons for this are many and varied, usually a crash means we did something wrong, but sometimes it might mean an exception was thrown and never caught or an API was misused. + +iOS allows you to extract crash logs from the device using itunes or xcode, this allows your beta testers to send you a log that allows you to gleam some information related to the cause of the crash. If you use Log.p() all your entries will appear in the device log (System.out will not appear). The log will also contain stacks indicating the thread stacks including the reason for the crash, this isn’t always helpful but sometimes can provide important clues as to what went wrong. Unfortunately for performance reasons XCode strips out the compiled binary and the stacks just contain memory addresses that provide very little indication applicable to your app. + +We now have a feature for pro users allowing them to build an unstripped binary, we are limiting it to pro users since the size of the binary is double and the so is the time it takes to produce such a binary (its a server hog). This can be achieved using the ios.no_strip=true build argument which should allow logs to include symbol information in them by default. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/creating-new-projects-with-old-templates.md b/docs/website/content/blog/creating-new-projects-with-old-templates.md new file mode 100644 index 0000000000..9c9a968679 --- /dev/null +++ b/docs/website/content/blog/creating-new-projects-with-old-templates.md @@ -0,0 +1,134 @@ +--- +title: Creating New Projects with Old Templates +slug: creating-new-projects-with-old-templates +url: /blog/creating-new-projects-with-old-templates/ +original_url: https://www.codenameone.com/blog/creating-new-projects-with-old-templates.html +aliases: +- /blog/creating-new-projects-with-old-templates.html +date: '2022-03-29' +author: Steve Hannah +description: Learn how to convert the old Codename One "ANT" project structure demos + to Maven projects using the Maven Migration Tool. +--- + +Learn how to convert the old Codename One "ANT" project structure demos to Maven projects using the Maven Migration Tool. + +![Creating New Projects with Old Templates - Codename One](/blog/creating-new-projects-with-old-templates/Creating-New-Projects-with-Old-Templates-Codename-One-1024x536.jpg) + +Since migrating to Maven, the recommended way to create a new Codename One project is using the [Codename One initializr](https://start.codenameone.com/) tool. It will generate a fresh, new Maven project for you based on a template of your choosing. In order to **not** overwhelm you, we have thus far kept the template selections in this tool to a minimum. At the time of this writing you can choose one of: + +1. ****Bare-bones template****: This will set you up with a simple “hello world” app, that you can customize as required. This is available in both Java and Kotlin flavours. + + +2. ****GRUB****: A complete sample restaurant delivery app. (Java only) + +3. ****CodeRAD MVC Starter Project****: A template based on the CodeRAD MVC library. + + +4. ****Tweet App****: A template for a Twitter-style app. Also uses the CodeRAD MVC library. + +There are many other demos and templates that have been developed over the years that are not listed here. For example, there are several projects listed in the [Codename One demos section](https://www.codenameone.com/demos.html) of the website. + +![](/blog/creating-new-projects-with-old-templates/demos-section.png) + +Figure 1. Demos listed in the Codename One demos section. + +Many other demos can be found amongst our [GitHub repositories](https://github.com/orgs/codenameone/repositories?q=demo&type=all&language=&sort=), and there are a smattering of older demos in the [codenameone-demos repository](https://github.com/codenameone/codenameone-demos) as well. + +Most of these use the old “ANT” project structure, so they require some surgery to convert them to the modern Maven structure. In this article I will describe how to convert these demos to Maven projects using the Maven Migration Tool. + +### Step 1: Install the Codename One Maven Migration Tool + +The Maven migration tool is a GUI application that converts Codename One ANT-based projects into Maven projects. + +Download it for Mac, Windows, and Linux [here](https://www.jdeploy.com/~cn1-maven-migration-tool). + +### Step 2: Download the Demo Project + +Once you have installed the migration tool, you should download the demo project that you wish to use as the basis for your app. As an example, I’ll use the [MSUIKit demo](https://www.codenameone.com/demos/msuikit-psd-template-port-to-cross-platform-pixel-perfect-codename-one-app-for-android-iphone-ios-etc.html). + +![](/blog/creating-new-projects-with-old-templates/msuikit.png) + +Figure 2. The MSUIKit demo + +You can download this demo by clicking the [Source link](https://github.com/codenameone/MaterialScreensUIKit), then click the “Code” menu in the upper right, and select “Download ZIP”. + +![](/blog/creating-new-projects-with-old-templates/download-zip.png) + +After you have downloaded the ZIP, extract it, so that you have the project in a folder on your local machine. + +### Step 3: Convert the Project in Maven Migration Tool + +Open up the Maven migration tool application that you installed in Step 1. + +![](/blog/creating-new-projects-with-old-templates/migration-tool-1.png) + +Figure 3. The Maven migration tool window + +You can select the project you want to convert by pressing the “Browse…​” button next to the “Source Project Path” field. Then select the “MaterialScreensUIKit” directory in the **file** dialog. + +After you have selected this project, the migration tool form should be updated to reveal fields to edit the “Main Class Name”, and “Package Name”. They will be pre-populated with the original values from the project you are migrating, but you can change these values as appropriate for your application. + +![](/blog/creating-new-projects-with-old-templates/migration-tool-2.png) + +Figure 4. The "App Details" section allows you to enter a package name and Main class name for your application. + +Before moving on, you should check that the “Destination Directory” field is set to the location where you want your new project to be saved. + +If all of your settings look good, press the “Create Project” button. After about ten seconds, you should see a message indicating that your project was created successfully. + +![](/blog/creating-new-projects-with-old-templates/success.png) + +When you click the “OK” button, it should open Finder (Mac) or Explorer (Windows) to the directory where the project was saved. You can now proceed to open this project in your preferred IDE. Personally I recommend IntelliJ, but NetBeans, Eclipse, and VSCode should all work fine also. For this article, I will use IntelliJ. + +### Step 4: Open the Project in your IDE + +Depending on your operating system, the steps to open the project in IntelliJ may vary. For example, on Mac, you can just drag the folder itself onto the IntelliJ icon in your Dock (assuming you have the IntelliJ icon in your Dock). Alternatively, you can open a command prompt and do: + +```javascript + + cd /path/to/theproject +idea + + +``` + +Alternatively, you can just open IntelliJ, and then use the “File” > “Open” menu to open the project directory. + +After the project opens, you should expand the “Maven” tab on the right side of the window to see all of the build targets available to you. + +![](/blog/creating-new-projects-with-old-templates/maven-sidebar.png) + +Figure 5. The "Maven" side bar includes build targets available. + +You should also see these build targets listed in the “Run” menu on the toolbar. “Run in Simulator” will be selected by default. If you press the “Run” button on the toolbar, it should launch the project in the simulator as shown below: + +![](/blog/creating-new-projects-with-old-templates/simulator.png) + +### References + +For more information about Codename One’s Maven support, see the [Codename One Maven developers guide](https://shannah.github.io/codenameone-maven-manual/). + +You might also check out the [Bare-bones project getting started tutorial](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html) for an introduction to working with Maven projects. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved here for historical context. New discussion happens in the Discussion section below._ + + +### **Bryan Buchanan** — June 10, 2022 at 7:48 am ([permalink](https://www.codenameone.com/blog/creating-new-projects-with-old-templates.html#comment-24538)) + +> Bryan Buchanan says: +> +> Excellent tool. Works really well. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcreating-new-projects-with-old-templates.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/crisp-cn1lib.md b/docs/website/content/blog/crisp-cn1lib.md new file mode 100644 index 0000000000..f992d7b6ef --- /dev/null +++ b/docs/website/content/blog/crisp-cn1lib.md @@ -0,0 +1,57 @@ +--- +title: Crisp cn1lib +slug: crisp-cn1lib +url: /blog/crisp-cn1lib/ +original_url: https://www.codenameone.com/blog/crisp-cn1lib.html +aliases: +- /blog/crisp-cn1lib.html +date: '2018-10-22' +author: Shai Almog +--- + +![Header Image](/blog/crisp-cn1lib/new-features-1.jpg) + +Crisp powers the chat button in the bottom right portion of our site. It also handles emails and a host of other great features. One feature we didn’t take advantage of is the mobile app support. To solve that we just issued a new [Crisp cn1lib](https://github.com/codenameone/CrispCodenameOneSDK) which we integrated into the new versions of our [Android](https://www.codenameone.com/blog/build-app-beta.html) and [iOS](https://www.codenameone.com/blog/build-app-on-ios.html) apps. + +You can install it yourself using the extension manager and use it with the instructions [here](https://github.com/codenameone/CrispCodenameOneSDK). + +There is some implementation detail related to the library which I think would be interesting to developers building similar solutions. + +### Why HTML/JS and Not Native? + +When I started the work of porting the library I looked at the Crisp native SDKs for iOS/Android. I even got some code working but as I looked through the actual SDK source code it became apparent that Crisps native SDKs for iOS and Android don’t leverage native functionality. This is perfectly OK as HTML/JS can deliver a fine experience for this type of app. + +However, its silly to wrap the native libraries when I can use HTML directly and get greater portability. As a result of that I threw away the code I wrote for the original integration and used the HTML approach. This highlights the importants of reviewing the implementation before we start implementing a cn1lib. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Boniface N. Githinji** — October 26, 2018 at 3:37 pm ([permalink](https://www.codenameone.com/blog/crisp-cn1lib.html#comment-24039)) + +> Boniface N. Githinji says: +> +> Great job Shai. I’d love to re-style the FAB button – change the bg color. Any pointers on how I could do this? I tried ‘Crisp.getInstance().chatFab().getAllStyles().setBgColor(0x24d07a);’ but this didn’t work. FAB still had the red color. +> +> Thank you. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcrisp-cn1lib.html) + + +### **Boniface N. Githinji** — October 26, 2018 at 3:44 pm ([permalink](https://www.codenameone.com/blog/crisp-cn1lib.html#comment-24064)) + +> Boniface N. Githinji says: +> +> Got it to work by overriding the ‘FloatingActionButton’ UUID. Changed BgColor to 24d07a. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcrisp-cn1lib.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/cross-platform-mobile-still-better-than-native-in-age-of-flat-design.md b/docs/website/content/blog/cross-platform-mobile-still-better-than-native-in-age-of-flat-design.md new file mode 100644 index 0000000000..e7c5a1c455 --- /dev/null +++ b/docs/website/content/blog/cross-platform-mobile-still-better-than-native-in-age-of-flat-design.md @@ -0,0 +1,145 @@ +--- +title: Cross Platform Mobile still Better than Naive in age of Flat Design +slug: cross-platform-mobile-still-better-than-native-in-age-of-flat-design +url: /blog/cross-platform-mobile-still-better-than-native-in-age-of-flat-design/ +original_url: https://www.codenameone.com/blog/cross-platform-mobile-still-better-than-native-in-age-of-flat-design.html +aliases: +- /blog/cross-platform-mobile-still-better-than-native-in-age-of-flat-design.html +date: '2016-09-26' +author: Shai Almog +--- + +![Header Image](/blog/cross-platform-mobile-still-better-than-native-in-age-of-flat-design/write-once-run-anywhere-is-better.jpg) + +A few years back [I wrote an article for O`Reilly](http://radar.oreilly.com/2013/11/wora-can-be-better-than-native.html) +covering the advantages of cross platform over native OS code. Almost 3 years have passed and a lot has changed +in our industry so I wanted to re-examine how this impacts my perspective on cross platform vs. native. + +I can sum up the sentiment in a single sentence: “Cross platform is both more essential & more practical than ever before!”. + +### Flat Design Simplified Portability + +Both iOS and Android applications are far more similar. Google releases material design applications for iOS without +major backlash as they don’t look out of place. Yes there are still platform sensibilities to take into account but +they are far fewer than they were three years ago. + +Flat design removed the clutter from applications making the functionality & clean design front and center. This +is wonderful for WORA tools. The focus on functionality allows WORA tools to reuse code and gain on native +developers. + +### Native Backlash + +Users would often complain about sub-par performance of WORA tools. This has been mitigated on two fronts. + +The tools themselves have improved by leaps and bounds, Codename One is far better than it was in 2013 and +other tools in the field have also improved tremendously. + +But the bigger change is in user sentiment, for every user who complains about “nativeness” you have another +user complaining vigorously about their platform not getting the same treatment. E.g. dropbox who has pretty good +native iOS/Android apps recently released an iOS app update that included a great feature: “Scan to PDF”. + +This feature would be very useful for me on Android but a quick search revealed that it isn’t available yet and that +the [community is pretty mad about this](https://www.dropboxforum.com/hc/en-us/community/posts/206158043-Document-scanning-not-for-android-). +This is about an Android port from a unicorn company that doesn’t lack for resources! + +Some people will always complain about an app that doesn’t look good or isn’t responsive but a lot of users +who don’t understand the technical details associate the word native with “fast, good looking & responsive” +which you can achieve without recoding the app 2-4 times…​ + +### Rise of Windows 10 + +Windows Phone is dead but Windows 10 is rising. In fact Microsofts surface is +[leading in the detachable keyboard tablet space](http://www.idc.com/getdoc.jsp?containerId=prUS41072516). +This specific segment is hugely important in the corporate world where access to legacy Windows software +is crucial. + +This means we now need to deal with 3 prominent platforms and stores instead of 2 (ignoring the Kindle or +similar Android stores for simplicity). + +Coding your app twice might have been reasonable but doing it three times and requiring two separate machines +(Mac and Windows) isn’t as practical. + +### Stability/Stagnation in Mobile OS’s + +Mobile changed very quickly in the past but over the past few years it didn’t innovate as much. Google & Apple +spent resources on watches, cars & glasses all of which didn’t take off. Mobile phone apps refined but didn’t change +in a fundamental way, this is good as a stable platform is much easier to track for cross platform developers. + +As I mentioned above platforms converged a lot. This is obvious in the UI level where iOS, Android & Windows look +more alike every day. But it’s also important in the underlying behavior. + +Android was remarkably flexible when it launched allowing background services to do just about anything. iOS was +far more restrictive, disallowing multitasking altogether in its initial launch. + +Both yielded to a common middle ground. Android placed restrictions on background processes to prevent wasted +battery with project doze. iOS added support for many use cases which are still not as flexible as activities and +services but provide almost all of the commonly needed use cases. + +Permissions and security also saw a similar convergence where Android shifted it’s over complicated and misunderstood +permissions system to one that is more similar to the one iOS has. + +These convergences make WORA (Write Once Run Anywhere) far easier as they allow developers to run get a similar +experience (e.g. permission prompts) across various devices. + +### Final Word + +Let’s be clear, if you pick a WORA solution. Any WORA solution. Some purists will notice and complain. + +If you miss a feature or even an entire platform people will complain. + +In the past a customer asked me “lets assume I have all the money in the world and no restrictions, should I use +native or Codename One?”. + +I gave the obvious answer and it stems from the [Tao of programming](http://huffman.sourceforge.net/tao/tao-of-programming.html) : + +> A manager went to the master programmer and showed him the requirements document for a new application. The manager asked the master: “How long will it take to design this system if I assign five programmers to it?” +> +> “It will take one year,” said the master promptly. +> +> “But we need this system immediately or even sooner! How long will it take if I assign ten programmers to it?” +> +> The master programmer frowned. “In that case, it will take two years.” +> +> “And what if I assign a hundred programmers to it?” +> +> The master programmer shrugged. “Then the design will never be completed,” he said. + +— Tao of programming – 3.14 + +The more resources we have the more time things take and the bigger the disaster (e.g. JavaFX). WORA tools +allow us to focus our attention on the product and the user not on the politics of Apple, Google or Microsoft. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chibuike Mba** — September 27, 2016 at 4:33 pm ([permalink](https://www.codenameone.com/blog/cross-platform-mobile-still-better-than-native-in-age-of-flat-design.html#comment-23172)) + +> Chibuike Mba says: +> +> Nice points Shai, no matter the tools you use some users will still complain. +> +> For me, its better to deploy on multiple platforms using WORA tools like Codename One rather than being stock in one platform with native. Though it depends on the scenario and who makes the decision. +> +> I enjoyed reading the Tao of Programming you referenced in this article, having read Tao Te Ching, the tonality was similar, it was fun and educating at the same time. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcross-platform-mobile-still-better-than-native-in-age-of-flat-design.html) + + +### **Hristo Vrigazov** — October 3, 2016 at 5:28 am ([permalink](https://www.codenameone.com/blog/cross-platform-mobile-still-better-than-native-in-age-of-flat-design.html#comment-23082)) + +> Hristo Vrigazov says: +> +> Thanks for awesome service and keep it up guys! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcross-platform-mobile-still-better-than-native-in-age-of-flat-design.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/css-in-cn1libs.md b/docs/website/content/blog/css-in-cn1libs.md new file mode 100644 index 0000000000..c3e906d82c --- /dev/null +++ b/docs/website/content/blog/css-in-cn1libs.md @@ -0,0 +1,73 @@ +--- +title: CSS in CN1Libs +slug: css-in-cn1libs +url: /blog/css-in-cn1libs/ +original_url: https://www.codenameone.com/blog/css-in-cn1libs.html +aliases: +- /blog/css-in-cn1libs.html +date: '2020-02-20' +author: Steve Hannah +--- + +![Header Image](/blog/css-in-cn1libs/css-in-cn1llibs.jpg) + +We’ve just added support for including CSS inside of Codename One library projects so that CSS styles can now be distributed inside a cn1lib. This opens up a world of possibilities for creating module UI libraries and themes. + +### How it works + +To begin, you just need to add a “css” directory inside your **Codename One Library** project, with a “theme.css” file in it. + +Add your CSS styles into the **theme.css** file, and build the library project. + +If you add this module to a Codename One application project, these styles will automatically be included. + +__ | If you try to install a cn1lib that includes CSS into a **Codename One application** project that doesn’t have CSS activated, it will fail. You must activate CSS in the application project first. +---|--- + +### Bonus Tip: Auto-Installing Library into Apps when Building Library + +This tip is for those of you who are building your own cn1libs. When I’m developing a CN1lib, I always have a separate application project that uses the lib. This is because you can’t test a cn1lib directly inside a library project. The cn1lib first has to be installed into application project before it can be used and tested. + +This can create a lot of manual steps each time you make changes to your cn1lib and want to test them out. You need to build the library project, then copy the cn1lib from the library’s dist directory, into the application project’s lib directory. Then you need to select “Refresh Cn1libs” from the Codename One menu in the IDE. + +As far as I’m concerned, anything more than a single button press is too much for being able to test my changes. Luckily its really easy to eliminate the extra steps by adding a small snippet into your library project’s build.xml file. + +At the end of the “jar” target, add the following: + + + + + +Now, whenever you build the library project, it will automatically copy it into your application project, and refresh its CN1libs, so that you can test your changes instantly. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — February 23, 2020 at 10:06 am ([permalink](https://www.codenameone.com/blog/css-in-cn1libs.html#comment-21390)) + +> [Francesco Galgani](https://lh6.googleusercontent.com/-4K0ax_DVJf4/AAAAAAAAAAI/AAAAAAAAAAA/AMZuuckEd1kcni0y8k6NMzNtxwOCEPatQQ/photo.jpg) says: +> +> Thank you, however this can cause that the cn1lib CSS conflict with existing CSS. Another tip for the developer of a cn1lib could be the use of an unique prefix for every CSS included in the cn1lib. That prefix could be the name of the cn1lib, for example. Do you agree? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcss-in-cn1libs.html) + + +### **Shai Almog** — February 24, 2020 at 3:06 am ([permalink](https://www.codenameone.com/blog/css-in-cn1libs.html#comment-21389)) + +> Shai Almog says: +> +> I think that just using a unique name for a CSS element should be enough for most cases although a library specific prefix would probably be healthy. +> I don’t think this is something we should force as we’d like the option for CSS to override global theme settings when required e.g. in the case of a theme library. E.g. a cn1lib that offers dark mode theming. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcss-in-cn1libs.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/customizing-themes-of-codename-one-apps.md b/docs/website/content/blog/customizing-themes-of-codename-one-apps.md new file mode 100644 index 0000000000..9e77100179 --- /dev/null +++ b/docs/website/content/blog/customizing-themes-of-codename-one-apps.md @@ -0,0 +1,175 @@ +--- +title: Customizing Themes Of Codename One Apps +slug: customizing-themes-of-codename-one-apps +url: /blog/customizing-themes-of-codename-one-apps/ +original_url: https://www.codenameone.com/blog/customizing-themes-of-codename-one-apps.html +aliases: +- /blog/customizing-themes-of-codename-one-apps.html +date: '2021-03-15' +author: Steve Hannah +description: Recipes to customize the look and feel of Codename One apps using Themes, + CSS, Styles, etc. +--- + +Recipes to customize the look and feel of Codename One apps using Themes, CSS, Styles, etc. + +The following recipes include tips on customizing the look and feel of Codename one apps using themes, CSS, styles, etc. + +### Platform-Specific Styling + +## Problem + +You have used CSS to style your app, and it looks great on some devices but not on others. You want to change the font size of some styles, but only on specific devices. + +## Solution + +Use CSS media queries to target styles at a specific device (e.g. desktop, tablet, or phone), platform (e.g. Android, iOS, Mac, Windows, etc…​), or device densities (e.g. low, medium, high, very high, etc..). + +## Example: A media query to override Label color on iOS only + +```css + + @media platform-ios { + Label { + color: red; + } +} + + +``` + +Media queries will allow you to target devices based on three axes: Platform, Device, and Density + +## Table 1. Platform Queries + +| Value | Description | +| --- | --- | +| platform-ios | Apply only on iOS | +| platform-and | Apply only on Android | +| platform-mac | Apply only on Mac desktop | +| platform-win | Apply only on Windows desktop | + +## Table 2. Device Queries + +| Value | Description | +| --- | --- | +| device-desktop | Apply only on desktop | +| device-tablet | Apply only on tablet | +| device-phone | Apply only on phone | + +## Table 3. Density Queries + +| Value | Description | +| --- | --- | +| density-very-low | Very low density 176x220 and smaller | +| density-low | Low density up to 240x320 | +| density-medium | Medium density up to 360x480 | +| density-high | High density up to 480x854 | +| density-very-high | Very high density up to 1440x720 | +| density-hd | HD up to 1920x1080 | +| density-560 | Intermediate density for screens between HD to 2HD | +| density-2hd | Double the HD level density | +| density-4k | 4K level density | + +You can combine media queries to increase the specificity. + +## Example: Targeting only 4k Android tablets + +```css + + @media platform-and, device-tablet, density-4k { + Label { + font-size: 5mm; + } +} + + +``` + +You can also combine more than one query of the same type to broaden the range of the query. + +For example, targeting only HD, 2HD, and 4K Android tablets: + +```css + + @media platform-and, device-tablet, density-4k, density-2hd, density-hd { + Label { + font-size: 5mm; + } +} + + +``` + +## Further Reading: + +[Media Queries Section of Codename One Wiki](https://github.com/codenameone/CodenameOne/wiki/css#media-queries) + +### Platform-Specific Font Scaling + +## Problem + +Your app looks great except that on desktop, the fonts are a little too small. If you could only scale the fonts to be 25% larger on the desktop, your app would be perfect. + +## Solution + +You can use font-scaling constants to scale all of the fonts in your stylesheet by a constant factor. You can use a “media-query-like” syntax to apply this scaling only on particular platforms, devices, or densities. + +## Example: Scaling Fonts to be 25% larger on desktop + +```css + + #Constants { + device-desktop-font-scale: "1.25"; +} + + +``` + +## Tip: + +> In most cases it is better to use standard media queries to apply styles which target specific platforms in a more fine-grained manner. + +## Further Reading: + +[Font-Scaling constants section of the Codename One Wiki](https://github.com/codenameone/CodenameOne/wiki/css#font-scaling-constants) +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved here for historical context. New discussion happens in the Discussion section below._ + + +### **ThomasH99** — March 16, 2021 at 8:07 am ([permalink](https://www.codenameone.com/blog/customizing-themes-of-codename-one-apps.html#comment-24414)) + +> ThomasH99 says: +> +> Great addition, really useful. Thanks! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcustomizing-themes-of-codename-one-apps.html) + + +### **Javier Anton** — March 24, 2021 at 9:06 am ([permalink](https://www.codenameone.com/blog/customizing-themes-of-codename-one-apps.html#comment-24417)) + +> Javier Anton says: +> +> Thanks, I rely on themes at the moment and kind of dread migrating to CSS. I know the clock is ticking and you will switch off support for themes at some point, so resources like these are great +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcustomizing-themes-of-codename-one-apps.html) + + +### **ThomasH99** — March 28, 2021 at 9:33 am ([permalink](https://www.codenameone.com/blog/customizing-themes-of-codename-one-apps.html#comment-24418)) + +> ThomasH99 says: +> +> Javier, I’m using CSS since quite some time, I found it easy to get started, and it’s a really nice way of working, especially with the live update (the simulator is updated as soon as you save the CSS file). This has made the workflow a LOT faster. The only slight concern I’ve come across is that since the CSS conversion creates every possible variation of the UIIDs (pressed ect), my generated .res becomes very big (280 uiids gives a .res of 400kb, no pictures). I define UIIDs for most of the individual elements based on their semantics and that might not be the best solution, but it makes it easy to tune individual styles whenever needed. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcustomizing-themes-of-codename-one-apps.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/cutting-psd-files.md b/docs/website/content/blog/cutting-psd-files.md new file mode 100644 index 0000000000..04b423bd2f --- /dev/null +++ b/docs/website/content/blog/cutting-psd-files.md @@ -0,0 +1,112 @@ +--- +title: Cutting PSD Files +slug: cutting-psd-files +url: /blog/cutting-psd-files/ +original_url: https://www.codenameone.com/blog/cutting-psd-files.html +aliases: +- /blog/cutting-psd-files.html +date: '2013-04-07' +author: Shai Almog +--- + +![Header Image](/blog/cutting-psd-files/cutting-psd-files-1.png) + +This post is inspired by a great post written by +[ +Tope +](http://www.appdesignvault.com/photoshop-crop) +, covering the slicing of a PSD image to produce small PNG images which you can later on use as image borders, backgrounds, icons etc. Tope’s technique is pretty simple and works rather well but I’d like to offer another technique as well as a better way to detect the proper layer you with to cut. + + + + +[ +![Picture](/blog/cutting-psd-files/cutting-psd-files-1.png) +](/img/blog/old_posts/cutting-psd-files-large-4.png) + +This post assumes you have a recent version of Photoshop installed and assumes you don’t know anything about Photoshop. So we start by opening the PSD file in Photoshop, this file is composed of layers. A single “component” is usually composed of multiple layers which you can show/hide by pressing the “eye” button in the layer view. + + + + +You can see the layer view by selecting Windows->Layers from the photoshop menu, on the right you can see the layers of a simple iPhone design that I have here. You will notice that every entry is collapsible. + +A common paradigm designers use is to create multiple screens/forms in a singled PSD + +and thus represent a “screen” (Form) of its own within the design. + + +So in order to see the other forms for those cases you can just hide/show each layer, in order to show individual components you can + +use the eye icon to get a specific component. + + +Now our goal is to find a specific set of layers relevant to us and “hide” everything else so we can get the particular component we need in isolation. + + +This is pretty easy when the design is small, but just locating the right layer becomes a HUGE hassle as the design gets complicated and deeply nested. + + +* * * + + + + +[ +![Picture](/blog/cutting-psd-files/cutting-psd-files-2.png) +](/img/blog/old_posts/cutting-psd-files-large-5.png) + +To find the layer matching a specific component we select the “Move Tool” from the toolbar and check the auto select option in the toolbar above, we then pick the “Layer” entry instead of group. + + +Now when we click an area on the screen the layer corresponding to this specific entry will be selected in the layer view and we could manipulate it. Notice that a component is often composed of multiple layers… We usually would want to hide things such as the text layers etc. for cases such as buttons where we would want to get the button alone so we can cut it into a 9-piece border, but we would want other layers. + + +* * * + + + + +[ +![Picture](/blog/cutting-psd-files/cutting-psd-files-3.png) +](/img/blog/old_posts/cutting-psd-files-large-6.png) + +Now say I want to extract an image that is comprised of the following 3 layers, I can select all 3 layers then right click on them (important! Notice that you need to click on the area where the text appears NOT on the icon of the layer, you will get a different context menu otherwise!). You will get an option to convert the layers to a smart object. + + +After converting to a smart object double click the layer icon (you will get a dialog with a message that is relevant only if you are interested in really changing the file), the standalone image will open in a separate tab and you will be able to use the Save As option and select PNG as the format. + + +* * * + +I hope this tutorial together with the very detailed tutorial from Tope will help you cut images from PSD’s more effectively and help you create better looking apps. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — September 30, 2013 at 3:28 am ([permalink](https://www.codenameone.com/blog/cutting-psd-files.html#comment-21890)) + +> Anonymous says: +> +> there is a nice alternative solution to do this process automatically, +> +> free little extension called Breeezy it adds to Photoshop the ability to export multiple layers in one click +> +> you can take a look +> +> [breeezyplugin.com]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fcutting-psd-files.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/dark-mode.md b/docs/website/content/blog/dark-mode.md new file mode 100644 index 0000000000..0c607d79db --- /dev/null +++ b/docs/website/content/blog/dark-mode.md @@ -0,0 +1,113 @@ +--- +title: Dark Mode +slug: dark-mode +url: /blog/dark-mode/ +original_url: https://www.codenameone.com/blog/dark-mode.html +aliases: +- /blog/dark-mode.html +date: '2020-06-25' +author: Shai Almog +--- + +![Header Image](/blog/dark-mode/dark-mode.jpg) + +We recently added support to detect whether a device is running in dark/light mode based on [this issue](https://github.com/codenameone/CodenameOne/issues/2979). Some of the code in the implementation is also derived from that issue submitted by [Javier](https://github.com/javieranton-zz). + +### Detecting Dark Mode + +Dark mode can be detected using APIs in the [CN](https://www.codenameone.com/javadoc/com/codename1/ui/CN.html) and [Display](https://www.codenameone.com/javadoc/com/codename1/ui/Display.html) classes. Specifically `isDarkMode()` and `setDarkMode(Boolean)`. + +Notice that `isDarkMode()` returns `Boolean` and not `boolean`. This means that `null` is a valid value for this method. The case of `null` indicates that dark mode detection isn’t available or isn’t working on this platform. + +You can override the dark mode setting for the platform using `setDarkMode()`. + +At this time dark mode detection only works on iOS, Android and JavaScript. We tried adding desktop support for that, but it proved a bit challenging. UWP detection isn’t supported at the moment. + +We don’t currently have an event based API for dark mode detection. While nice, this isn’t universally supported and can be circumvented with a simple timer. + +### Native/Builtin Theme Support + +Ideally, the app would just switch to dark mode seamlessly but right now this isn’t the case. The theme constant `darkModeBool` changes some deep core theme styles to match dark mode if `isDarkMode()` is true. In the future it might trigger a dark version of the native theme. At the moment we don’t have dark versions of the themes. + +To create a dark version of your app create a new resource file for dark mode and load it conditionally based on dark mode. You can do the same for CSS by creating a CSS file called `dark.css` and editing your `build.xml` file to replicate the CSS conversion line. Specifically: + + + + + + + + + + + + + + + + + +Then in Java code you can load a different theme and change themes at runtime using our builtin theming. + +__ | You can put two themes in a single resource file but since most settings can’t be reused between dark/light the benefit is limited +---|--- + +You can load a new resource file theme by using: + + + theme = UIManager.initFirstTheme("/resource"); + +You can then apply the theme to the current form dynamically using `refreshTheme()` on the form. + +### Moving Forward + +We hope to add additional dark/light templates and also port the native themes to include dark counterparts. This work isn’t scheduled yet but this is the direction. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Mohammed Hussein** — August 28, 2022 at 8:55 pm ([permalink](https://www.codenameone.com/blog/dark-mode.html#comment-24542)) + +> Mohammed Hussein says: +> +> Hi Shai, just landed on this blog!! while searching on an issue with CSS theme switching, here’s what I did and please keep me right if misunderstood: +> * I migrated successfully to Maven using my existing theme.css, +> * following the KitchenSink demo, I try to add another dark-them.css, using : +> ` +> Resources resources = Resources.openLayered( "/dark-theme"); +> ` +> +> Sadly, I keep getting “/dark-theme.res not found” and no sign to the .res file on my folders! +> +> Also, please note that, build.xml does not exists on my Maven project!, +> +> Can you please advise with any hints on how to switch my theme with CSS? +> +> Best regards, +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdark-mode.html) + + +### **Mohammed Hussein** — September 1, 2022 at 8:46 am ([permalink](https://www.codenameone.com/blog/dark-mode.html#comment-24544)) + +> Mohammed Hussein says: +> +> Thank you Shai, +> +> For those landing on this and using Maven, please note the following: +> +> Compiling the dark theme is not yet supported by the Maven plugin. An issue for this can be track on: +> +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdark-mode.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/data-loading-placeholders.md b/docs/website/content/blog/data-loading-placeholders.md new file mode 100644 index 0000000000..03783b89f2 --- /dev/null +++ b/docs/website/content/blog/data-loading-placeholders.md @@ -0,0 +1,135 @@ +--- +title: Using Component Placeholders While Loading Data +slug: data-loading-placeholders +url: /blog/data-loading-placeholders/ +original_url: https://www.codenameone.com/blog/data-loading-placeholders.html +aliases: +- /blog/data-loading-placeholders.html +date: '2019-12-05' +author: Steve Hannah +--- + +![Header Image](/blog/data-loading-placeholders/new-features-2.jpg) + +In my last post I introduced the new CN.invokeWithoutBlocking() method as a means of ensuring that your UI construction code doesn’t run into any “blocking” that could negatively affect user experience. In cases where you need to perform a network request to help build your UI, I offered some recommendations for moving blocking code out of the critical paths. One recommended pattern was to insert placeholder content into your components, which you replace with the actual data once it has been received from the server. That pattern goes something like: + + + Form f = new Form("Hello", BoxLayout.y()); + Label nameLabel = new Label(); + nameLabel.setText("placeholder"); + AsyncResource request = fetchDataAsync(); + request.ready(data -> { + nameLabel.setText(data.getName()); + f.revalidateWithAnimationSafety(); + }); + f.add(nameLabel); + f.show(); + +The concept here is that, the `fetchDataAsync()` method is performing an asynchronous network request in the background but returns an AsyncResource object immediately which will be notified when the response if received. Therefore, the contents of the `ready( data → {…​})` block are executed some time after the form has already been built and shown. + +This solved a significant user experience problem, in that the form can be shown to the user immediately without waiting for the network request to complete. However, it introduced a new problem, which is that our `nameLabel` is displaying placeholder text for some period of time before it is replaced with the actual data. + +To help solve this problem, I have added some new progress animations that are specifically designed to be used as placeholders while a component’s data is being loaded. These animations include methods for easily swapping themselves with other components while they are loading, and then seamlessly swapping back once the component is finished loading. Currently there are two ProgressAnimation classes: + + 1. **CircleProgress** – A circle that progressively draws itself then erases itself. This is a variation on the classic infinite progress animation, but it is more flexible than the built-in `InfiniteProgress` class. + + 2. **LoadingTextAnimation** – This animation appears to be a paragraph of text that is being typed progressively one word at a time – except instead of words, it just renders filled rectangles. This is useful for indicating that a block of text is loading. + +### Example using CircleProgress + + + Form f = new Form("Hello", new BorderLayout(BorderLayout.CENTER_BEHAVIOR_CENTER_ABSOLUTE)); + Form prev = CN.getCurrentForm(); + Toolbar tb = new Toolbar(); + f.setToolbar(tb); + tb.addCommandToLeftBar("Back", null, evt->{ + prev.showBack(); + }); + Label nameLabel = new Label(); + $(nameLabel).setAlignment(CENTER); + nameLabel.setText("placeholder"); + f.add(BorderLayout.CENTER, nameLabel); + // Replace the label by a CircleProgress to indicate that it is loading. + CircleProgress.markComponentLoading(nameLabel) + .getStyle().setFgColor(0xff0000); + + AsyncResource request = fetchDataAsync(); + request.ready(data -> { + nameLabel.setText(data.getName()); + + // Replace the progress with the nameLabel now that + // it is ready, using a fade transition + CircleProgress.markComponentReady(nameLabel, CommonTransitions.createFade(300)); + }); + + f.show(); + +And the result looks like: + + +Your browser does not support the video tag. + +### Example Using LoadingTextAnimation + + + Form f = new Form("Hello", new BorderLayout(BorderLayout.CENTER_BEHAVIOR_SCALE)); + Form prev = CN.getCurrentForm(); + Toolbar tb = new Toolbar(); + f.setToolbar(tb); + tb.addCommandToLeftBar("Back", null, evt->{ + prev.showBack(); + }); + SpanLabel profileText = new SpanLabel(); + + profileText.setText("placeholder"); + f.add(BorderLayout.CENTER, profileText); + // Replace the label by a CircleProgress to indicate that it is loading. + LoadingTextAnimation.markComponentLoading(profileText); + + AsyncResource request = fetchDataAsync(); + request.ready(data -> { + profileText.setText(data.getProfileText()); + + // Replace the progress with the nameLabel now that + // it is ready, using a fade transition + LoadingTextAnimation.markComponentReady(profileText, CommonTransitions.createFade(300)); + }); + + f.show(); + +And the result looks like: + + +Your browser does not support the video tag. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — February 8, 2020 at 7:21 am ([permalink](https://www.codenameone.com/blog/data-loading-placeholders.html#comment-21378)) + +> [Francesco Galgani](https://lh6.googleusercontent.com/-4K0ax_DVJf4/AAAAAAAAAAI/AAAAAAAAAAA/AMZuuckEd1kcni0y8k6NMzNtxwOCEPatQQ/photo.jpg) says: +> +> Thank you Steve! +> What is the utility of `CommonProgressAnimations.EmptyAnimation`? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdata-loading-placeholders.html) + + +### **Steve Hannah** — February 10, 2020 at 12:49 pm ([permalink](https://www.codenameone.com/blog/data-loading-placeholders.html#comment-21382)) + +> [Steve Hannah](https://lh3.googleusercontent.com/a-/AAuE7mBmUCgKSZtJ2cqeHgj6bdPY2AAQ10roHlMpgRWc) says: +> +> Sometimes you may just want to hide a component until its data is properly loaded, but you don’t want to show any visual animation. That’s when EmptyAnimation is useful. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdata-loading-placeholders.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/data-processing-in-codename-one-apps.md b/docs/website/content/blog/data-processing-in-codename-one-apps.md new file mode 100644 index 0000000000..3dca8b0118 --- /dev/null +++ b/docs/website/content/blog/data-processing-in-codename-one-apps.md @@ -0,0 +1,253 @@ +--- +title: Data Processing in Codename One apps +slug: data-processing-in-codename-one-apps +url: /blog/data-processing-in-codename-one-apps/ +original_url: https://www.codenameone.com/blog/data-processing-in-codename-one-apps.html +aliases: +- /blog/data-processing-in-codename-one-apps.html +date: '2021-03-25' +author: Steve Hannah +description: The following recipes relate to data processing and conversion in Codename + One apps. This includes parsing data like JSON, HTML and XML. +--- + +The following recipes relate to data processing and conversion in Codename One apps. This includes parsing data like JSON, HTML and XML. + +### Parsing HTML + +## Problem + +You want to parse some HTML content into a data structure. You can’t simply use the [XMLParser](https://www.codenameone.com/javadoc/com/codename1/xml/XMLParser.html) class because the content is not well-formed XML, but you would like to be able to work with the parsed document using the same tools (e.g. [Result](https://www.codenameone.com/javadoc/com/codename1/processing/Result.html) and [Element](https://www.codenameone.com/javadoc/com/codename1/xml/Element.html).) + +## Solution + +Use the HTMLParser class from the [CN1HTMLParser cn1lib](https://github.com/shannah/CN1HTMLParser). It contains a simple API for parsing an HTML string into an [Element](https://www.codenameone.com/javadoc/com/codename1/xml/Element.html), the same type of element that [XMLParser](https://www.codenameone.com/javadoc/com/codename1/xml/XMLParser.html) returns. + +## Usage Example: + +```java + + HTMLParser parser = new HTMLParser(); + +Element root = parser.parse(htmlString).get(); (1) +Result r = Result.fromContent(root); + +// Now modify the document +// In this example we're going to replace image src with placeholders +// so we can load them separately. +List images = r.getAsArray("//img"); +int index = 0; +List toLoad = new ArrayList<>(); +if (images != null) { + for (Element img : images) { + String src = img.getAttribute("src"); + if (src.startsWith("http://*/") || (!src.startsWith("http://") && !src.startsWith("data:") && !src.startsWith("https"))) { + img.setAttribute("id", "nt-image-"+index); + toLoad.add(src); + img.setAttribute("src", ""); + index++; + } + } +} + +// Now write the document as well-formed XML. +XMLWriter writer = new XMLWriter(true); +String pageContent = writer.toXML(root); + + +``` + +The `parse()` method returns an Async promise. If you want to use it synchronously, you can call `get()`, which will wait until parsing is done. + +## Alternate Async Usage + +The above example uses the `get()` method to wait until the result is ready, but you can use the parser asynchronously as well: + +```java + + parser.parse(htmlString).ready(root->{ + // root is the root Element of the document. +}); + + +``` + +## Discussion + +The HTMLParser class wraps an off-screen BrowserComponent to use the platform’s native webview to actually parse the HTML. It then serializes the DOM as XML, which is then re-parsed using the Codename One XML parser. There are pitfalls to this approach, including performance (it takes time to pass data back-and forth between a webview, after all), and possibly different results on different platforms. + +## NOTE + +> The Codename One core library also includes an HTMLParser class at `com.codename1.ui.html.HTMLParser`. This parser is meant to be used as part of the deprecated HTMLComponent class, which is a light-weight web view component that used to be used on platforms that didn’t have a native webview, e.g. J2ME. Now all modern platforms have a native webview, so this component isn’t used much. Additionally the HTMLParser class in that package doesn’t support all HTML, and will fail in strange ways if you try to use it headlessly. + +## Further Reading + +[XMLParser Javadocs](https://www.codenameone.com/javadoc/com/codename1/xml/XMLParser.html) – Since the output of HTMLParser is the same as XMLParser, you can find some useful examples in the XMLParser javadocs. + +### Using the Clipboard + +## Problem + +You want to copy and paste to and from the system clipboard. + +## Solution + +Use the `Display.copyToClipboard()` and `Display.getPasteDataFromClipboard()` to copy and paste to/from the system clipboard respectively. + +## Example: Copying to the Clipboard + +```java + + Display.getInstance().copyToClipboard("Some text to copy"); + + + +``` + +## Example: Copying text from clipboard into Label + +```java + + Object pasteData = Display.getInstance().getPasteDataFromClipboard(); +Label text = new Label(); +if (pasteData instanceof String) { + text.setText((String)pasteData); +} else { + ToastBar.showInfoMessage("Paste data is not text"); +} + + +``` + +## IMPORTANT + +> In the Javascript port we are restricted by the browser’s sandbox. We can’t ****just**** access the system clipboard data for security reasons. However, if the user initiates a paste via `Ctrl-V`, `Command-V`, `Edit` → `Paste` etc, the system clipboard contents will be loaded into the Codename One clipboard, so that the next time you call `getPasteDataFromClipboard()`, it will include those contents. +> +> +> You can use `Form.addPasteListener(ActionListener)` to be notified when the clipboard contents are updated via this method so that you can respond appropriately - usually by calling `getPasteDataFromClipboard()` and doing something with the data. + +## Full Example allowing copy and paste using the Clipboard API + +```java + + package com.codename1.samples; + +import com.codename1.components.ToastBar; +import static com.codename1.ui.CN.*; +import com.codename1.ui.Display; +import com.codename1.ui.Form; +import com.codename1.ui.Dialog; +import com.codename1.ui.Label; +import com.codename1.ui.plaf.UIManager; +import com.codename1.ui.util.Resources; +import com.codename1.io.Log; +import com.codename1.ui.Toolbar; +import java.io.IOException; +import com.codename1.ui.layouts.BoxLayout; +import com.codename1.io.NetworkEvent; +import com.codename1.ui.Button; +import com.codename1.ui.CN; +import com.codename1.ui.TextArea; +import com.codename1.ui.TextField; +import com.codename1.ui.layouts.GridLayout; + +public class ClipboardSample { + + private Form current; + private Resources theme; + + public void init(Object context) { + // use two network threads instead of one + updateNetworkThreadCount(2); + + theme = UIManager.initFirstTheme("/theme"); + + // Enable Toolbar on all Forms by default + Toolbar.setGlobalToolbar(true); + + // Pro only feature + Log.bindCrashProtection(true); + + addNetworkErrorListener(err -> { + // prevent the event from propagating + err.consume(); + if(err.getError() != null) { + Log.e(err.getError()); + } + Log.sendLogAsync(); + Dialog.show("Connection Error", "There was a networking error in the connection to " + err.getConnectionRequest().getUrl(), "OK", null); + }); + } + + public void start() { + if(current != null){ + current.show(); + return; + } + Form hi = new Form("Hi World", BoxLayout.y()); + TextField text = new TextField(); + Button copyBtn = new Button("Copy"); + copyBtn.addActionListener(evt->{ + Display.getInstance().copyToClipboard(text.getText()); + }); + Button pasteBtn = new Button("Paste"); + pasteBtn.addActionListener(evt->{ + if ("html5".equalsIgnoreCase(CN.getPlatformName())) { + // In the browser, we don't have permission, in general, to read from the clipboard + // but the user can initiate a paste using Ctrl-V or Cmd-V, or Edit > Paste, + // and the data will be received in the paste listener. + Dialog.show("Help", "Please key-codes or Edit > Paste to paste content.", "OK", null); + return; + } + handlePaste(text); + }); + + // The paste listener is informed when the user initiates a paste using + // key-codes or browser menu items (Edit > Paste). This is currently only + // used by the Javascript port. + hi.addPasteListener(evt->{ + handlePaste(text); + }); + + hi.add(text) + .add(GridLayout.encloseIn(2, copyBtn, pasteBtn)); + + hi.show(); + } + + /** + * Pastes the current clipboard data as text into the given TextArea. + * @param text The textarea to paste into + */ + private void handlePaste(TextArea text) { + Object pasteData = Display.getInstance().getPasteDataFromClipboard(); + if (pasteData instanceof String) { + text.setText((String)pasteData); + } else { + ToastBar.showInfoMessage("Paste data is not text"); + } + } + + public void stop() { + current = getCurrentForm(); + if(current instanceof Dialog) { + ((Dialog)current).dispose(); + current = getCurrentForm(); + } + } + + public void destroy() { + } + +} + + +``` + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/date-util.md b/docs/website/content/blog/date-util.md new file mode 100644 index 0000000000..e04ed59d57 --- /dev/null +++ b/docs/website/content/blog/date-util.md @@ -0,0 +1,86 @@ +--- +title: Date Util +slug: date-util +url: /blog/date-util/ +original_url: https://www.codenameone.com/blog/date-util.html +aliases: +- /blog/date-util.html +date: '2018-04-04' +author: Shai Almog +--- + +![Header Image](/blog/date-util/new-features-3.jpg) + +Timezones suck. Especially daylight saving. I don’t mind moving the clock or losing an hour of sleep as much as the programming bugs related to that practice. The thing that sucks even more is Java’s old date/time API. +This was publicly acknowledged by the Java community with JSR 310 which replaced the Java Date & Time API’s however due to its complexity we still don’t have it yet. As a small workaround we created a small API to perform some common date calculations. + +`DateUtil` allows you to check if a day is in the daylight saving era or if it isn’t. It works consistently on all platforms without a problem e.g.: + + + DateUtil du = new DateUtil(); + Log.p("Currently in daylight savings time? "+du.inDaylightTime(new Date())); + Log.p("Offset: "+du.getOffset(new Date().getTime())); + + Date dec30 = new Date(1483056000000l); + Log.p("Dec 30 is daylight savings time? "+du.inDaylightTime(dec30)); + Log.p("Offset: "+du.getOffset(dec30.getTime())); + +The `DateUtil` constructor can take a `TimeZone` as parameter. Without it, it uses the default `TimeZone`. + +### Completion Listeners + +Media allows us to track whether it finished playing or not when we first set it up. After that point you were on your own. + +Last week we added a new ability to bind a completion listener after the fact and potentially have multiple listeners: + + + MediaManager.addCompletionHandler(myMediaObject, () -> Log.p("This is a runnable callback")); + +### Partial Round + +I’ve been working on improving [this issue](https://github.com/codenameone/CodenameOne/issues/2350). The UI part isn’t there yet but the code is…​ + +The gist of it is that with the round rect border we currently have 3 options: + + * All corners should be rounded + + * Only the top corners + + * Only the bottom corners + +The issue pointed out a use case for some of the corners and I can think of a case where I’d like the left or right corners rounded…​ + +With that in mind I decided the right thing to do is offer control over individual corners. This is possible only in code at the moment but would hopefully make it to the designer tool too at some point: + + + RoundRectBorder rb = RoundRectBorder.create().bottomLeftMode(false); + +This would create a border whose corners are round except for the bottom left corner. While I was working on the class I also improved the performance/memory overhead of the border for solid colors. + +### Support for PATCH HTTP Request In Rest + +The `Rest` class now [supports the HTTP PATCH method](https://github.com/codenameone/CodenameOne/issues/2372) which was missing from the API before. It’s not as common as other API’s so it went unnoticed for a while. + +It works pretty much like every other [Rest API request](https://www.codenameone.com/blog/terse-rest-api.html). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — April 9, 2018 at 12:07 pm ([permalink](https://www.codenameone.com/blog/date-util.html#comment-23804)) + +> Francesco Galgani says: +> +> Thank you very much for the partial RoundRectBorder, it works as expected. I hope you can integrate it in the Designer 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdate-util.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/debating-brendan-eich-over-android-openjdk-move.md b/docs/website/content/blog/debating-brendan-eich-over-android-openjdk-move.md new file mode 100644 index 0000000000..e13be38ab5 --- /dev/null +++ b/docs/website/content/blog/debating-brendan-eich-over-android-openjdk-move.md @@ -0,0 +1,210 @@ +--- +title: Debating Brendan Eich Over Android-OpenJDK Move +slug: debating-brendan-eich-over-android-openjdk-move +url: /blog/debating-brendan-eich-over-android-openjdk-move/ +original_url: https://www.codenameone.com/blog/debating-brendan-eich-over-android-openjdk-move.html +aliases: +- /blog/debating-brendan-eich-over-android-openjdk-move.html +date: '2016-01-05' +author: Shai Almog +--- + +![Header Image](/blog/debating-brendan-eich-over-android-openjdk-move/dukeandroid.png) + +I had a big post ready for today but after a long twitter debate with +[@BrendanEich](https://twitter.com/BrendanEich) I had to write a followup as +twitter is a poor medium for that level of debate. +This started with a [ +blog post from Andreas Gal](http://andreasgal.com/2016/01/05/oracle-sinks-its-claws-into-android/) who effectively took the exact opposite stance to mine on +[Google’s move to OpenJDK](/blog/analysis-google-moving-to-openjdk-what-that-really-means.html). +Then Mr. Eich picked it up: + +> .[@mosheeshel](https://twitter.com/mosheeshel) [@enleeten](https://twitter.com/enleeten) [@hhariri](https://twitter.com/hhariri) [@Codename_One](https://twitter.com/Codename_One) We don't know enough yet, but I agree with [@andreasgal](https://twitter.com/andreasgal) that code changes show cost+risk go up. +> +> — BrendanEich (@BrendanEich) [January 5, 2016](https://twitter.com/BrendanEich/status/684454476028227584) + +To be fair I’m biased. I work on a [cross platform mobile toolchain](/) and I’m an ex-Sun +guy. But I think that the fact that the senior Java/Android community has embraced this change as a positive one +says a lot. Also Android compatibility is crucial in our line of business where we need code to work for all +versions of Android without a problem… +Lets go over the claims made both on Twitter and in the article. + +#### Oracle sinks its claws into Android + +Using a title like this is misleading, clickbait & antagonistic. +I don’t think Oracle made any friends with the lawsuit, overall the vibe in the Java community is that +this was a mistake that didn’t help anyone. The thing is that OpenJDK is GPL and so Oracle doesn’t really +“own” it and doesn’t really gain much except in maybe some “respect”. + +OpenJDK is GPL+CPE so Google can use it without paying Oracle a dime (just like Linux distros do). It also +features a patent grant which means that if Google passes the TCK’s (meaning they are Java compatible which +is a **good thing(tm)**) they will receive a license for the patents and Oracle can’t legally sue +them over patents used in the VM! + +So effectively the title is pretty wrong, Google gets newer up to date Java code for free and the Java OSS community +can focus on one code base (for security analysis, performance etc.) instead of two. Compatibility will rise +although its already there or 99.99% there. + +#### This Was Forced Thru Legal Process + +Totally true. That doesn’t make it bad for us although one could wish that peace was reached without the legal system. +Google took a calculated risk when Android was young which made a lot of sense when Sun owned Java. +The reason for taking a specific action doesn’t mean its bad, I would wager that one of the reasons Google +avoided adopting OpenJDK in the past was legal as well. + +#### Apache License vs. GPL License + +As I was writing this a [ +great article was posted that pretty much answers this better than I could](http://ebb.org/bkuhn/blog/2016/01/05/jdk-in-android.html). I chose to leave my +thoughts below since its simpler to read. +Its harder to get people to adopt GPL, but they did it with Linux despite there being BSD licensed alternatives +that are pretty good. Google already used Linux as the core so already has some GPL code. +The original post already corrected the fact that OpenJDK didn’t exist when Android came out. But that wasn’t +the sticking point with Sun. Google wanted the Apache license and Sun was making a lot of money over mobile +so this was a big problem/conflict. + +The reason Google insisted on Apache was due to operators who were the gate keepers Google needed to get +past to control mobile. Now that its already in and controls the market adding more GPL code is meaningless just +as operators have gone down in their power since the days Android launched. Overall this changed nothing, +in Android M you had X lines of GPL code from Linux and now you will have more lines of GPL+CPE code +no real difference. + +#### All this code and technology churn will have massive implications for Android + +> [@Codename_One](https://twitter.com/Codename_One) [@deanrl](https://twitter.com/deanrl) [@enleeten](https://twitter.com/enleeten) [@hhariri](https://twitter.com/hhariri) To recap, [@andreasgal](https://twitter.com/andreasgal) & I say MLOCs of forced change carry hi incompat risk, all agree that'd suck. +> +> — BrendanEich (@BrendanEich) [January 6, 2016](https://twitter.com/BrendanEich/status/684609887817445376) + +This is far from accurate. To be fair, only Google engineers know the approximate extent of work and only +after the fact will we fully know the implications. However, I’ve ported JVM’s for years both at Sun +& at Codename One. I’m very familiar with the issues of getting code to work on the desktop +VM and the mobile VM and specifically with Android issues. +From my experience Android VM compatibility issues are 80% vendor/operator issues (weird stuff with +device specific behaviors) and 20% issues in the `android.*` packages. We ran into no +issue whatsoever with the harmony code being different from Java 7 or 8 in terms of compatibility. +Its possible that such edge cases exist but I doubt it would be a big deal and it would allow better +server/mobile shared code. + +> [@deanrl](https://twitter.com/deanrl) [@Codename_One](https://twitter.com/Codename_One) [@mosheeshel](https://twitter.com/mosheeshel) [@enleeten](https://twitter.com/enleeten) [@hhariri](https://twitter.com/hhariri) [@andreasgal](https://twitter.com/andreasgal) Developer reward is later and second or third order. Risk+cost first order. +> +> — BrendanEich (@BrendanEich) [January 5, 2016](https://twitter.com/BrendanEich/status/684520929800491008) + +The existing Harmony classes are old and stale, no one touched them in years so a big change of removing +and replacing them with other classes will take some effort from Google’s developers. That’s a fact. +Its years worth of changes that now Google needs to do in a single swoop but its something Google +**should** have done in the past to bring newer classes/features into place. The alternatives +are doing nothing or doing this slowly at their own pace both of which would be bad. + +Java has amazing TCK’s that check compatibility, the likelyhood of something breaking is relatively low. +We have been porting Java code to Android for years with absolutely no issues related to these API’s so on +the surface this looks like something that would go unnoticed for most existing apps. If something will stop +working or behave radically different Google has the ability to work in compatibility mode for that specific +API builtin to their manifest target SDK system. + +While this is big change in terms of lines of code most of those lines are already written and well tested so +it looks like a big change but is much smaller in scope than the LOC would make it seem. Prior changes made +by Google even for Marshmallow are huge earth shattering changes to the basic permissions system of Android +that has been in place since 1.x days. That is probably a far bigger problem for everyday Android developers +than this change. +Device compatibility with no-brand devices on the far east market and non-google devices are also far bigger problems +for an Android developer than this will ever be. + +> [@deanrl](https://twitter.com/deanrl) [@Codename_One](https://twitter.com/Codename_One) [@mosheeshel](https://twitter.com/mosheeshel) [@enleeten](https://twitter.com/enleeten) [@hhariri](https://twitter.com/hhariri) [@andreasgal](https://twitter.com/andreasgal) 2/ Bill Joy of Sun persuaded us to kill Kipp's VM as bug4bug is impossible. +> +> — BrendanEich (@BrendanEich) [January 6, 2016](https://twitter.com/BrendanEich/status/684526309540679681) + +I worked at Sun for years and never got facetime with Bill Joy… Ugh. +What was true in 1995 is no longer true today, Java now has a robust TCK and language specification. It +has quite a few separate compliant VM’s and is pretty well understood. I think Google did an amazing +job at compliance and its clear they followed the JVM specification well. + +#### This Change Won’t Benefit Users + +> [@deanrl](https://twitter.com/deanrl) [@Codename_One](https://twitter.com/Codename_One) [@mosheeshel](https://twitter.com/mosheeshel) [@enleeten](https://twitter.com/enleeten) [@hhariri](https://twitter.com/hhariri) [@andreasgal](https://twitter.com/andreasgal) Developer reward is later and second or third order. Risk+cost first order. +> +> — BrendanEich (@BrendanEich) [January 5, 2016](https://twitter.com/BrendanEich/status/684520929800491008) + +While there are some changes that benefit users directly, most software development changes don’t. Not +all developers benefit from every language/API feature either. +Users will benefit from the fact that code bases are unified and security auditing will now focus on a more +uniform code base. A lot of the standard Java tools might work better with Android as a result e.g. the current +level of Android profiling support is HORRIBLE when compared to desktop Java or even iOS. +iOS has excellent profiling support thanks to d-trace (technology from Sun) so hopefully we’ll see an eventual +peace process and more collaboration to benefit everyone. + +#### Final Word + +> [@Codename_One](https://twitter.com/Codename_One) [@mosheeshel](https://twitter.com/mosheeshel) [@enleeten](https://twitter.com/enleeten) [@hhariri](https://twitter.com/hhariri) [@andreasgal](https://twitter.com/andreasgal) Any nontrivial work raises costs+risks. As technologist & founder I see it plainly. +> +> — BrendanEich (@BrendanEich) [January 5, 2016](https://twitter.com/BrendanEich/status/684457722071269376) + +I think this sums up a lot of the claims. Yes this will take Google some effort. Yes a few apps might be +affected, I’d wager this would be far less than those affected by the Marshmallow changes and Google +has the tools to alleviate a lot of that problems (sdk version hints). +Would Google have done it without the lawsuit? +Maybe… If there was no lawsuit and Java 8 was out, maybe Google would have adopted OpenJDK or maybe +they would have dedicated the engineering effort to add this support into Android’s Harmony. Either way +a lot of engineering effort would have gone out whether the lawsuit was there or not. + +Google’s current version of Java is old and stale, replacing it is a good thing for everyone even though its +not free of any costs. But everything has a cost and this one is probably worth paying in the long run. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Bo83** — January 6, 2016 at 5:20 pm ([permalink](https://www.codenameone.com/blog/debating-brendan-eich-over-android-openjdk-move.html#comment-22182)) + +> Bo83 says: +> +> great article and I get the overall gist of what you are saying but I would need a dictionary of terms and a day to study it to really read this article and understand it intelligently and thoroughly. I just want to write code with the latest and greatest; can’t we all just get along 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdebating-brendan-eich-over-android-openjdk-move.html) + + +### **Shai Almog** — January 6, 2016 at 5:28 pm ([permalink](https://www.codenameone.com/blog/debating-brendan-eich-over-android-openjdk-move.html#comment-22522)) + +> Shai Almog says: +> +> Thanks. +> +> It was actually fun debating him since he is a good debater (and REALLY smart). I just really can’t stand debating with “catch phrases”. Technical debates require proof and context which is problematic in twitter. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdebating-brendan-eich-over-android-openjdk-move.html) + + +### **Chad** — January 6, 2016 at 10:56 pm ([permalink](https://www.codenameone.com/blog/debating-brendan-eich-over-android-openjdk-move.html#comment-22389)) + +> Chad says: +> +> IMO phrases like “Java has amazing TCK’s that check compatibility” and “It has quite a few separate compliant VM’s” are disingenuous. This is what killed Harmony in the first place, they couldn’t get a TCK because Oracle didn’t like their license. I would love to make my own open source compatible JVM, but I will never see the TCK. I think it’s harmful to pretend it’s a “good thing(tm)” that implementations have to pass a hidden test suite whose keyholders may make demands of your software. Sure it means I can’t call my JVM “Java”, but that’s the problem here. There is only one open-source compliant JVM implementation base that I am aware of, and that is a bad thing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdebating-brendan-eich-over-android-openjdk-move.html) + + +### **Shai Almog** — January 7, 2016 at 3:37 am ([permalink](https://www.codenameone.com/blog/debating-brendan-eich-over-android-openjdk-move.html#comment-22671)) + +> Shai Almog says: +> +> Interesting point, I skimmed over the angle of a VM implementer as its probably less interesting to most of the readership! +> +> First let me clarify that my bias is towards Google as I think they were in the right side technically as clean room implementations should be legal. We also use some code from Harmony in Codename One so I’m very much in favor of that. +> +> Sun was the one that refused the TCK license to Harmony, its an important distinction with all the people pilling hate on Oracle I don’t think we need to add something else there 😉 +> (Although to be fair Oracle didn’t fix anything in this regard) +> +> We make our own VM too (ParparVM) so obviously to be compliant we also need to pass the TCK now (see my previous analysis on the subject) which might also be a problem. If you use OpenJDK and its license you can probably apply to access for that as I’m sure Google has. Since they are/were a Java licensee I think they might already have that access. +> +> For a small VM (like us) this is more problematic so I totally agree that the opaqueness of the TCK process is a problem. FYI I did “see” and worked a lot with the TCK on older versions of Java to get our VM’s thru compliance. For Sun’s VM’s it was mostly trivial since the JIT/VM was reused but there are a lot of weird edge cases tested by the TCK. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdebating-brendan-eich-over-android-openjdk-move.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/debug-a-codename-one-app-on-an-android-device.md b/docs/website/content/blog/debug-a-codename-one-app-on-an-android-device.md new file mode 100644 index 0000000000..32f4309f76 --- /dev/null +++ b/docs/website/content/blog/debug-a-codename-one-app-on-an-android-device.md @@ -0,0 +1,106 @@ +--- +title: Debug a Codename One app on an Android Device +slug: debug-a-codename-one-app-on-an-android-device +url: /blog/debug-a-codename-one-app-on-an-android-device/ +original_url: https://www.codenameone.com/blog/debug-a-codename-one-app-on-an-android-device.html +aliases: +- /blog/debug-a-codename-one-app-on-an-android-device.html +date: '2016-05-30' +author: Shai Almog +--- + +![Header Image](/blog/debug-a-codename-one-app-on-an-android-device/mqdefault.jpg) + +Debugging Codename One apps on iOS devices has been documented well with a video for years, we didn’t +spend too much time outlining the Android counterpart mostly because we didn’t really use it as much and it +was far simpler. + +As Android Studio launched this actually became really easy as it was possible to actually open the gradle project +in Android Studio and just run it. But due to the fragile nature of the gradle project this stopped working for our recent +builds, this works for some cases but is a bit of a flaky touch & go. + +__ | If +[these instructions](http://stackoverflow.com/questions/34430404/how-to-build-the-native-android-sources-from-codename-ones-build-server) +work for you then you can ignore the video/instructions below. However, if they don’t then keep reading +---|--- + +Google has the tendency to change things frequently which makes documenting a process to work +with Android much harder than the iOS equivalent. +The method outlined in the [“how do i” video](/how-do-i-debug-on-an-android-device.html) that we just launched +should work regardless of future changes. It might not be the best way to do this but it’s simple and it works. + +Here are the steps highlighted in the video: + + 1. Check the include source flag in the IDE and send a build + + 2. Download the sources.zip result from the build server + + 3. Launch Android Studio and create a new project + + 4. Make sure to use the same package and app name as you did in the Codename One project, select to not create an activity + + 5. Unzip the sources.zip file and copy the `main` directory from its `src` directory to the Android Studio projects `src` directory +make sure to overwrite files/directories. + + 6. Copy its `libs` directory on top of the existing libs + + 7. Copy the source gradle files dependencies content to the destination gradle file + + 8. Connect your device and press the Debug button for the IDE + +__ | You might need to copy additional gradle file meta-data such as multi-dexing etc. +---|--- + +You might not need to repeat the whole thing with every build. E.g. it might be practical to only copy the `userSources.jar` +from the libs directory to get the latest version of your code.and you can copy the `src/main` directory to get our +up to date port. + +### Refinement + +There are many edge cases and hints that probably don’t fit into this process, let us know in the comments below +about the difficulties and success you’ve had with this process and also provide tips about simpler hacks to +build the code for device. + +There is a portion we didn’t get into with the video, copying updated sources directly without sending a build. +This is possible if you turn on the new Android Java 8 support. At this point you should be able to remove the libs +jar file which contains your compiled data and place your source code directly into the native project for debugging +on the device. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Nilmar Castro** — December 28, 2016 at 12:58 pm ([permalink](https://www.codenameone.com/blog/debug-a-codename-one-app-on-an-android-device.html#comment-22976)) + +> Nilmar Castro says: +> +> Hello Shai, +> I’m starting at codenameone. I am not fluent in English but I understand very well the majority of the tutorials that are presented. However in this specifically the presenter speaks very fast and it is not possible for me to understand as necessary. +> +> Is there any other? +> +> Thank you very much +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdebug-a-codename-one-app-on-an-android-device.html) + + +### **Shai Almog** — December 29, 2016 at 5:41 am ([permalink](https://www.codenameone.com/blog/debug-a-codename-one-app-on-an-android-device.html#comment-23219)) + +> Shai Almog says: +> +> Hi, +> I prefer her voice to mine (I narrated the old videos) but thanks 😉 +> +> In the newer videos we have subtitles that contain the full text that you can read in the youtube page. You can also see the full transcript of every one of the new videos in their “How Do I?” page. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdebug-a-codename-one-app-on-an-android-device.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/debugging-in-production-how-to-move-fast-without-breaking-things.md b/docs/website/content/blog/debugging-in-production-how-to-move-fast-without-breaking-things.md new file mode 100644 index 0000000000..8b77bd10ea --- /dev/null +++ b/docs/website/content/blog/debugging-in-production-how-to-move-fast-without-breaking-things.md @@ -0,0 +1,212 @@ +--- +title: Debugging in Production – How to move fast without breaking things +slug: debugging-in-production-how-to-move-fast-without-breaking-things +url: /blog/debugging-in-production-how-to-move-fast-without-breaking-things/ +original_url: https://www.codenameone.com/blog/debugging-in-production-how-to-move-fast-without-breaking-things.html +aliases: +- /blog/debugging-in-production-how-to-move-fast-without-breaking-things.html +date: '2021-08-11' +author: Shai Almog +description: Learn how we debug our backend servers and provide fast updates without + breaking deployments. +--- + +Learn how we debug our backend servers and provide fast updates without breaking deployments. + +![Debugging in Production - How to move fast without breaking things](/blog/debugging-in-production-how-to-move-fast-without-breaking-things/Debugging-in-Production-How-to-move-fast-without-breaking-things-1024x280.jpeg) + +Mark Zuckerberg famously quipped that Facebook works under the “Move fast and break things” motto. We can write all the unit tests in the world, have the largest QA pipeline but still bugs slither into production. That’s just a fact of life which he chose to celebrate. + +When dealing with an incredibly complex system like we have in [Codename One](https://www.codenameone.com/) this can be the difference between releasing an update and doing nothing. + +## If you are a visual learner check out the following video: + +### Disaster Strikes + +The problem with this approach becomes apparent when we have a bug in production. Normally, a bug that would go through staging, QA and tests wouldn’t be too horrible… But since it’s a production only bug you’re often faced with two options: + +## • Revert — That might not be an option for all cases • Find/Implement a Fix + +Notice that I left out “reproduce it locally”. This is often not an option for production bugs which work on a separate DB in “real world” conditions. In our case local debugging is very difficult due to the multiple separate servers that hand off tasks to one another. + +The second option is usually best but it includes a huge risk: what if the fix fails? + +Since production deployment is often a slow process that requires a QA cycle this compounds the problem. You make a fix then have to wait for hours only to find out that you got it wrong… This used to be us. + +### Enter Lightrun + +So a couple of years ago I met two young founders who had an idea on how to solve this problem. Essentially, it’s a new kind of debugger that works very differently from a regular debugger. + +The gist of this is that your app constantly runs in a production debugging mode, the overhead is barely noticeable. A secure agent connects the app to the cloud and lets you debug in a special way. + +e.g. instead of breakpoints you have snapshots. They don’t “break”. They provide you with a stack trace of the thread and the variable state at the given time. You can also inject log statements, count executions and even do simple profiling on methods or blocks of code. + +I was so impressed by this idea that I decided to join the team and now hold two jobs (at [Codename One](https://www.codenameone.com/) and at [Lightrun](https://www.lightrun.com/)). The cool thing is that my job at [Codename One](https://www.codenameone.com/) is now much easier thanks to [Lightrun](https://www.lightrun.com/). + +### Bugs in Production… + +90% of my work at [Codename One](https://www.codenameone.com/) is putting out fires. A subscriber writes to our support complaining about a failure of a build or push servers etc. This used to be very hard to debug. We would spend hours reading huge logs and guessing + +Then we’d deploy additional logs, ask the user to send a new build and then reread the logs to figure out what the hell went wrong. Some of the guessing is always there but with Lightrun the whole process is practically instant. + +With Lightrun we can just set a conditional snapshot e.g. + +![Debugging a failure in push](/blog/debugging-in-production-how-to-move-fast-without-breaking-things/Debugging-a-failure-in-push.png) + +Debugging a failure in push + +In the case above I can grab a snapshot when a specific user sends a push. This is a conditional breakpoint, that’s a useful tool when debugging locally. It’s an indispensable tool when debugging in production. We only want to see the information related to a specific user and not all users… + +When the snapshot hits we end up with a stack trace similar to this one (I blacked out private information in the image). + +![Snapshot Stack](/blog/debugging-in-production-how-to-move-fast-without-breaking-things/Snapshot-Stack.png) + +Snapshot Stack + +Notice that a Snapshot looks just like a regular breakpoint. It’s missing the threads and you can’t step over. But you can walk the stack and inspect the values of fields/variables etc. when the application is still running… +Pretty darn useful! + + +Instead of stepping over you can just add multiple snapshots or even inject logs to print information when hitting a specific line. Including simple expressions such as: `The value is {obj.getValue()}`. + + +My immediate thought was “won’t this be expensive?”. + + +It isn’t. If we have a very complex/expensive expressions that prints too much per second or uses problematic (e.g. recursive) logic, Lightrun is smart enough to limit itself so the expression won’t take too much CPU. It protects you from shooting yourself in the foot… + + +As a result of that there’s no noticeable performance overhead and you can work without worrying. But I digress, lets go back to the push server example above. + +## Unexpected Bug + +When I started this post I wanted to reproduce a debugging session for a user problem but as I was grabbing the screenshots for the session I noticed something weird in the stack. The value of `subscriptionLevel` was gibberish. It was way too large. + + +Turns out we had a bug in reading the user subscription level when sending push messages. That meant that quotas and rate limits weren’t applied at all in our push server! + + +I’m sure we lost income because of this bug, users whose subscription elapsed could still send push messages at volume without a problem. Ugh! + + +This is one of the coolest benefits of Lightrun, it lets you see clearly into the running system and verify your expectations. + +## Expected User Problem + +The real problem I debugged relates to that line above. A user stopped getting iOS push messages. I just placed a Snapshot (AKA breakpoint) with his token, then inspected the values sent to the push server. + +I could then see the URL of the push certificate and could instantly verify that it expired. This was easier to do than debugging locally! + +## The Deeper Pipeline + +User issues are very important but issues that no one is aware of are possibly even more important… + +![Exception Monitoring](/blog/debugging-in-production-how-to-move-fast-without-breaking-things/Exception-Monitoring.png) + +Exception Monitoring + +Lightrun also provides a way to detect exceptions (caught or uncaught). We can review the stack traces periodically to see if there are errors that we didn’t detect. + +This isn’t a unique feature to Lightrun, but it fits perfectly as you can easily trace a problem you saw in the stack traces. + +## Metrics + +Lightrun also includes metrics such as counters, tictocs and method duration measurements. + +This is super useful for micro-benchmarks in production but we don’t need this as much in Codename One. Our backend is relatively simple and these never came up. + +### Installing Lightrun + +So, there has to be a downside right? + +Installing the plugin in the IDE and signing up is very easy… But agent setup is still challenging. I spent a lot of time trying to get it to work on all our servers. + +Admittedly the Codename One architecture is pretty complex filled with a lot of legacy and pre-docker deployment choices. Prepare yourself for a bit of work. It might be trivial but you might need some help from the web chat support channel (which is super responsive). + +![Signup Page on app.lightrun.com](/blog/debugging-in-production-how-to-move-fast-without-breaking-things/Signup-Page-on-app.lightrun.com_.png) + +Signup Page on app.lightrun.com + +Once you sign up at you get a wizard that verifies you performed the steps correctly: + +![Install the Plugin and Login](/blog/debugging-in-production-how-to-move-fast-without-breaking-things/Install-the-Plugin-and-Login.png) + +Install the Plugin and Login + +To pass the first step you need to install the IntelliJ plugin from the [marketplace](https://plugins.jetbrains.com/plugin/16477-lightrun). + +You then need to restart the IDE, open the Lightrun tool window on the right hand side and press the login button. + +Once logged in, the Next button in the wizard will become enabled and you could move on to the agent installation step. This is the hard part… + +![Agent Install instructions](/blog/debugging-in-production-how-to-move-fast-without-breaking-things/Agent-Install-instructions.jpeg) + +Agent Install instructions, notice I erased private information + +The agent is typically installed on your server and not on your local machine. So when I reached this page “Mac” was selected. I had to explicitly select the Linux page and copy the script that installs the agent on Linux machines. + +The next step is to SSH to the machine and run the script. It creates an “agent” directory which we’ll use when binding the agent. + +The gist of this is that we need to add the `-agentpath` argument to the JVM. That’s very simple if your deployment has a “java” command invocation at some point but if your running as a service or within a container that might not be so simple. + +Once you do that the “Next” option will be enabled and you would be able to use Lightrun. + +But there are more complex cases, I would recommend reviewing the list [here](https://docs.lightrun.com/). + +One example is our older Tomcat server used for push. I had to edit `catalina.sh` and add something like this: + +```bash + + JAVA_OPTS="$JAVA_OPTS -agentpath:/home/username/agent/lightrun_agent.so= --lightrun_extra_class_path=/home/username/apache-tomcat/webapps/myapp.war" + + +``` + +Notice the extra option of `--lightrun_extra_class_path` (that’s 2 minus signs) which we use to explicitly state the classpath. You might need that if things aren’t auto-detected properly. +This let the agent run but I got no variables in my stack traces… +Turns out I had to recompile the code with full debug options turned on `-g`. This was a bit of a challenge in Maven. The solution was to add these properties: + +```xml + + + ... + true + true + lines,vars,source + lines,vars,source + + + +``` + +You can test that `-g` is missing using code like this: + +```bash + + javap -classpath Project/target/classes -v pkg.ClassName | grep LocalVariableTable + + + +``` + +If this prints nothing then the class doesn’t contain debug information. + +Again, this is an involved process. I strongly suggest engaging support while going through it. + +### TL;DR + +The reason we don’t rush to production is the tedious and slow process of fixing production issues. But this creates an overly complex multi-branch support structure that ends up making matters worse. + +If we can debug quickly in the production and fix right away our overall stability increases while keeping a low overhead. + +IMO Deploying a server today without debugging tools is akin to coding without an IDE. You can do that but you’re missing out on modern advancements in our field. + +At Codename One, our user support tasks are resolved much faster and more effectively thanks to Lightrun. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/deeper-in-the-renderer.md b/docs/website/content/blog/deeper-in-the-renderer.md new file mode 100644 index 0000000000..252261731b --- /dev/null +++ b/docs/website/content/blog/deeper-in-the-renderer.md @@ -0,0 +1,317 @@ +--- +title: Deeper In The Renderer +slug: deeper-in-the-renderer +url: /blog/deeper-in-the-renderer/ +original_url: https://www.codenameone.com/blog/deeper-in-the-renderer.html +aliases: +- /blog/deeper-in-the-renderer.html +date: '2013-12-17' +author: Shai Almog +--- + +![Header Image](/blog/deeper-in-the-renderer/deeper-in-the-renderer-1.jpg) + + + + + +![List](/blog/deeper-in-the-renderer/deeper-in-the-renderer-1.jpg) + + + + +When Chen initially drew up the proof of concept for LWUIT he copied the concept of list renderers from Swing, this was one of the most hotly debated issues between us. Whether we should aim for familiarity for Swing users or simplify what has always been an API that novices wrestle with. We eventually went with the familiarity approach, a decision we both agree today was short sighted. + + +Unfortunately changing the renderer API isn’t practical at this stage but we simplified a lot thanks to the GenericListCellRenderer which powers GUI builder list renderers. We simplified this further with the MultiList component which has a default renderer that’s pretty powerful to begin with. + + +However, this simplicity has resulted in developers using lists without + +quite understanding why they behave in this way. In a normal container all components are kept in a Tree like hierarchy that we can render (essentially similar to DOM). A list however doesn’t contain any components within it so it can hold a million entries with the same overhead it would have when holding 100 entries. + + +It works like this: + + + 1. +The EDT (event dispatch thread) asks the List to paint itself. + + 2. +The List asks the ListModel for the values of the currently visible entries. + + 3. +The List asks the renderer for a component representing every value (the same instance is recycled and discarded). + + 4. +This List paints the renderer as a rubber stamp for every single value. + + + + +So if the model has 1m entries we don’t need to create 1m components since we will reuse the renderer for every entry. We also don’t render elements that are invisible. + +There are problems with this model though: + + * +Since the renderer is “stamped” (drawn then used for a different value) adding a listener to a component within the list won’t do what you expect. + + * +Obviously individual elements within the list entry can’t get focus and can’t be edited + + + * +Within a List all entries have to be the exact same width/height. Otherwise its very expensive for us to calculate the list offset. ContainerList allows for variable height list but its performance/functionality is equivalent to Container so the benefits aren’t great. + + * +The performance of the model & the renderer must be very high otherwise the whole list will be impacted. + + * +Its hard to create animations (since there is no state). + + +You might be asking yourself: + +Why should I use a List? Why not just use a List or a Container with BoxLayout Y? + + + +That’s actually our recommendation for most cases, List is often too much of a hassle for some use cases and we try to avoid it in many applications. It is now also possible to create +[ +long scrolling containers +](http://www.codenameone.com/3/post/2013/09/till-the-end-of-the-form.html) +relatively easily although you might see performance degrading after a while. + + + +However List does have some serious advantages: + + * Scale – it scales well to huge lists and maintains speed. + * Flexibility – list can be flicked to horizontal mode, center selection behavior and other such capabilities. + * MVC – the list makes working with a data model really easy, if you are well versed with MVC this could be a very powerful + +So assuming you pick list lets see how you can make better use of it. + + +H + +ow do you deal with events on a button click within a list renderer? + + +So assuming I have a list renderer that has a button named X on the the side, dealing with this differs between a GUI builder app and a handcoded app. + + + +For a GUI builder app use the standard action listener for the list and within the action listener just write: + + +* * * + +Notice that the method above will not work for MultiList or a list containing MultiButton’s since those are composite components and can’t be separated to an individual component within. + + + + + + +If you are building a handcoded renderer this is a bit harder: + + + + +There are a few other features in the generic list cell renderer that aren’t well documented: + + * The UIID of the renderer is based on the UIID of the renderer component we also add a focus component to the list whose UIID is based on: selected.getUIID() + “Focus”. So if your selected renderer container has the UIID MyRenderer, then you focus component will have the UIID MyRendererFocus. + + + + * +Items are always overriden by their hashtable/map value even when they are missing. So if you place an icon in the renderer but don’t put the icon value in the hashtable model it will be removed. + +A solution is to just name the component with the word fixed in the end (case insensitive) as in iconFixed. This means that the value you give the icon in the renderer won’t change. + + * +You can disable/enable entries within the list by using map.put( + +GenericListCellRenderer.ENABLED, Boolean.FALSE). Notice that once you do this you must do this for all the entries otherwise the renderers “rubber stamp” behavior will repeat the status of the last entry. + * You can implement a “Select All” entry for a checkbox list by using map.put(GenericListCellRenderer.SELECT_ALL_FLAG, Boolean.TRUE). This is pretty useful if you have a checkbox list. + * You can place the entry number within the list by creating a component named $number. It will start with 1 as the offset and not with 0. + * If you want to provide a different value when an entry is selected (e.g. different image when clicked) you can use # in front of the name e.g. to allow Icon to have a different image when selected put a value into #Icon. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — December 18, 2013 at 6:59 pm ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-24235)) + +> Anonymous says: +> +> Any chance of some sample code snippets for the “few other features in the generic list cell renderer that aren’t well documented” +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Anonymous** — December 19, 2013 at 3:19 am ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-21904)) + +> Anonymous says: +> +> They are all listed below with the relevant code where applicable. Which one of the bullets isn’t clear? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Anonymous** — December 19, 2013 at 3:22 am ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-21845)) + +> Anonymous says: +> +> the last two. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Anonymous** — December 19, 2013 at 3:27 am ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-21766)) + +> Anonymous says: +> +> There is no code involved for the first. In the GUI builder just place a component and name it $number. In the UI this will be rendered as 1, 2, 3 etc. based on the offset. +> +> The second case allows you to provide different values for selected/unselected states. So if you have a model with values on the keys of the hashtable that you want to appear differently when pressed you can use that. A common use case is a different icon when the entry is selected (to match the colors) so normally I would place the icon as hash.put(“icon”, myUnselectedIcon); which will work both for selected/unselected states of the renderer. If I want a different icon design for the selected state I can use: hash.put(“#icon”, mySelectedIcon) as well. This will appear when the entry is selected. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Anonymous** — May 10, 2014 at 5:43 am ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-22013)) + +> Anonymous says: +> +> Hi, +> +> I have noticed that the “setFocus(Boolean focus)” is deprecated. I am currently using this to show the selected cell in a list (custom cell renderer based upon the default renderer). +> +> Unfortunately I can not find the alternative method when the setFocus should disappear. +> +> Can u provide some insight into this?? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Anonymous** — May 10, 2014 at 12:00 pm ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-21660)) + +> Anonymous says: +> +> Good question! +> +> We deprecated this method since people kept using it instead of requestFocus() for standard components. However, the renderer is indeed a special case where it is needed. +> +> Unfortunately there is no way in Java to indicate “don’t use this method here but only use it there” so we use the relatively coarse tool of deprecation. In hindsight we should have done renderers completely differently if at all but that is already water under the bridge. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Anonymous** — August 14, 2014 at 2:21 am ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-22144)) + +> Anonymous says: +> +> how to add different online images on each items of list ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Anonymous** — August 14, 2014 at 3:46 am ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-22005)) + +> Anonymous says: +> +> Set a different URL for the URLImage attribute in the model. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Anonymous** — August 14, 2014 at 5:41 am ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-21444)) + +> Anonymous says: +> +> I have used container which contains labels with name address and image. And want to use this container in list row and set image to image label and set address to address label. +> +> I am able to pass address to its label with hash_table in model as shown below. +> +> hash_table.put(“address”,”Nepal”); +> +> hash_table.put(“image”,”res_Image”); +> +> But problem is unable to pass online image +> +> can you give me simple codes for using online image in list ? +> +> And how to use URL Image in model (by code) ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Kaneda** — December 11, 2015 at 1:18 pm ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-21623)) + +> Kaneda says: +> +> I want to create a list of event like attach picture, i read this page i know i must not use List to build that, but do you have an example, a tutorial to do ? +> +> Thanks you +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Shai Almog** — December 12, 2015 at 5:30 am ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-22221)) + +> Shai Almog says: +> +> I would just create a box layout container similar to the PropertyCross demo with containers within it. +> Every container would have the image label on top in the center with some padding defined to take up the right size and background image behavior defined as “SCALE_TO_FIT” which will allow the image on top to look like that. +> I noticed that the Oct 23rd container has a carousel, if you need that to animate/move manually that is also easily doable thru replace animation. +> +> The bottom container can be a standard BoxLayout.X_AXIS with two BoxLayout.Y_AXIS within it. The first box Y would container the date as month string and number and the second would contain the title/subtitle (possibly as span label). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Kaneda** — December 14, 2015 at 11:10 am ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-22300)) + +> Kaneda says: +> +> I try it 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Kaneda** — December 14, 2015 at 4:07 pm ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-21499)) + +> Kaneda says: +> +> It works well 🙂 , and i use : +> +> Label myLabel = new Label(“My Title”); +> ImageDownloadService.createImageToStorage(thumb_url, myLabel, guid, new Dimension(Display.getInstance().getDisplayWidth(), Display.getInstance().getDisplayHeight())); +> +> But, the text of the label doesn’t display, how can I display the text hover the image. I think the image is not a background image. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + + +### **Shai Almog** — December 15, 2015 at 5:15 am ([permalink](https://www.codenameone.com/blog/deeper-in-the-renderer.html#comment-21490)) + +> Shai Almog says: +> +> I think the text is implicitly set to blank on download. +> +> Try placing a label with a text in a Container next to a label with the downloadable image. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeeper-in-the-renderer.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/default-static-methods-in-interfaces.md b/docs/website/content/blog/default-static-methods-in-interfaces.md new file mode 100644 index 0000000000..b3fc805de2 --- /dev/null +++ b/docs/website/content/blog/default-static-methods-in-interfaces.md @@ -0,0 +1,82 @@ +--- +title: Default & Static Methods In Interfaces +slug: default-static-methods-in-interfaces +url: /blog/default-static-methods-in-interfaces/ +original_url: https://www.codenameone.com/blog/default-static-methods-in-interfaces.html +aliases: +- /blog/default-static-methods-in-interfaces.html +date: '2016-04-12' +author: Shai Almog +--- + +![Header Image](/blog/default-static-methods-in-interfaces/java-8-lambada.png) + +In our original [Java 8 support announcement](/blog/java-8-support.html) post we specifically mentioned the +lack of streams but completely missed the fact that default/static native interfaces didn’t work. This is now fixed +thanks to an alert community member who pointed that out. + +It seems that these features are turned off by default for [retrolambda](https://github.com/orfjackal/retrolambda) +due to limitations that require a clean build to get them to work. This is no limitation for the Codename One +build server architecture so these features should work just fine for Codename One apps. + +### What are Default Interface Methods? + +Default interface methods allow you to add new methods to an interface and provide a default implementation. +This effectively enables us to move an API forward without breaking compatibility with someone who implemented +this interface. E.g. : + + + public interface DefaultInterfaceTest { + String method(); + + default String methodWithArg(String arg) { + return method(); + } + } + +This isn’t as important for most developers as we normally can just add a new method and solve the issue. +However, in the future as we move the implementation of Codename One to Java 8 syntax this will be a huge +boost as it will allow us to add methods to older interfaces such as [PushCallback](https://www.codenameone.com/javadoc/com/codename1/push/PushCallback.html). + +### What are Static Interface Methods + +Static interface methods are generally just static methods. In many cases we just hide static methods within +clases but sometimes that doesn’t make sense. E.g. the [Push](https://www.codenameone.com/javadoc/com/codename1/push/Push.html) class +is entirely composed of static methods and doesn’t make much sense as a standalone class. We could have +rolled all the methods within the class into the interface as static methods and eliminated the class entirely. + +This isn’t necessarily “good practice” but for some use cases this might be a better place to hold the method. + +E.g.: + + + public interface StaticInterfaceTest { + String method(); + + static String getNotNull(StaticInterfaceTest it, String def) { + String s = it.method(); + if(s == null) return def; + return s; + } + } + +You can read about default and static interface methods in the [Java Tutorial](https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html). + +### Switch to Full Java 8? + +As implied above we would get quite a bit of value from switching the code base of Codename One itself to Java 8. +Right now we still support building Java 5 apps and would probably not change that before 3.4 rolls out as our +current goals are stability more than anything else. However, once 3.4 rolls out we might implicitly make all +builds use Java 8 features and switch the internal code base to use it. + +Even if you use an old Java 5 project the builds should still work fine after such a transition and you won’t be forced +to switch, however, this will allow us to use features such as default methods to implement some capabilities we +need. It will also make out lives slightly easier by allowing us to use lambdas in our core implementation. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/default-validation-emblem.md b/docs/website/content/blog/default-validation-emblem.md new file mode 100644 index 0000000000..afec758c1a --- /dev/null +++ b/docs/website/content/blog/default-validation-emblem.md @@ -0,0 +1,41 @@ +--- +title: Default Validation Emblem +slug: default-validation-emblem +url: /blog/default-validation-emblem/ +original_url: https://www.codenameone.com/blog/default-validation-emblem.html +aliases: +- /blog/default-validation-emblem.html +date: '2016-12-05' +author: Shai Almog +--- + +![Header Image](/blog/default-validation-emblem/validation-emblem.png) + +The validation framework makes it easy to verify input quickly and effectively. Up until now you had to define +an emblem in order to create an error icon and if you didn’t you had to define an “Invalid” UIID for every entry. +This exists by default for text fields and other types but is still a big hassle just to check that we have a valid +email…​ + +The main reason for this is that when we introduced the validation framework we hadn’t yet integrated the +material icons into Codename One, this was remedied and starting with the next update we’ll have a default +emblem. Notice that if you replace it manually your emblem will still be used…​ + +However, we also changed the default behavior as a result. In the past we defaulted to `HighlightMode.UIID` +which makes a lot of sense when you don’t have an emblem. This default no longer makes sense and so +we now have `HighlightMode.EMBLEM` as the default. + +So if your code relies on the default behavior of the validator this will no longer behave in the same way. The +workaround is actually really simple, just add the call: + + + myValidator.setValidationFailureHighlightMode(Validator.HighlightMode.UIID); + +To force the same behavior as before. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/demo-section-russian-guide.md b/docs/website/content/blog/demo-section-russian-guide.md new file mode 100644 index 0000000000..df9c17ebac --- /dev/null +++ b/docs/website/content/blog/demo-section-russian-guide.md @@ -0,0 +1,38 @@ +--- +title: Demo Section & Russian Guide +slug: demo-section-russian-guide +url: /blog/demo-section-russian-guide/ +original_url: https://www.codenameone.com/blog/demo-section-russian-guide.html +aliases: +- /blog/demo-section-russian-guide.html +date: '2015-04-29' +author: Shai Almog +--- + +![Header Image](/blog/demo-section-russian-guide/picture.png) + +We are working on a new [demos](/demos.html) section for the website that will highlight the demos for +Codename One more thoroughly. Thanks to the new JavaScript port we can actually show the demos live in +action but that creates a bit of a problem since people often jump to the conclusion that Codename One +uses web technologies which it does not. + +Currently the demos section is pretty bare mostly because the JavaScript port still has a lot of bugs and missing +features. It is moving in leaps and bounds though and we are pretty confident that we will have all the major +demos up in the demo section within a short while. However, if you are familiar with the existing demos checking +out their JavaScript counterpart (and the desktop builds as well) will show you what we can accomplish with these +ports. + +### Developer Guide Translation + +A comment on our [developer guide announcement](/blog/new-developer-guide.html#comment-1993360936) +caught us a bit by surprise. It seems a community member +[translated the guide to Russian](http://wiki.ftp27host.ru/index.php?title=Codename1:%D0%98%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D1%8F_%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA%D0%B0) +which is pretty cool! + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/deploy-same-mobile-app-template-multiple-times.md b/docs/website/content/blog/deploy-same-mobile-app-template-multiple-times.md new file mode 100644 index 0000000000..8757cd8d77 --- /dev/null +++ b/docs/website/content/blog/deploy-same-mobile-app-template-multiple-times.md @@ -0,0 +1,130 @@ +--- +title: Deploy the Same Mobile App/Template Multiple Times +slug: deploy-same-mobile-app-template-multiple-times +url: /blog/deploy-same-mobile-app-template-multiple-times/ +original_url: https://www.codenameone.com/blog/deploy-same-mobile-app-template-multiple-times.html +aliases: +- /blog/deploy-same-mobile-app-template-multiple-times.html +date: '2016-09-25' +author: Shai Almog +--- + +![Header Image](/blog/deploy-same-mobile-app-template-multiple-times/clone-app.jpg) + +We often build one app and sell it to multiple customers. After all, most customers ask for similar things with minor +changes. E.g. if I build a restaurant app and then sell it to one establishment I can then resell it to another with almost +no change at all…​ + +Another common use case is the demo or free version of a paid app, you want to reuse as much of the work as possible +without maintaining two code bases. + +This question has come up quite a few times in the forums and most recently again +[on stackoverflow](http://stackoverflow.com/questions/39505331/managing-demo-full-version-of-my-app-in-codename-one). +It’s something we need to document better so here is a brief tutorial. + +### How does the Appstore “Know”? + +The first thing we need to understand is how the appstore identifies your application. + +Pretty much all apps use a unique identifier string that is similar to package names, which we map to the main +application package name. + +__ | Apple doesn’t allow underscores in these names, Java doesn’t allow the minus character `-` so avoid both +---|--- + +### Getting Started + +Lets assume we created an app for acme corporation under the package `com.acme.apps.supercoolapp`. We +now want to sell a similar app to +[Evil Corp.](https://www.rottentomatoes.com/tv/mr-robot/) (please no spoilers for those who didn’t see this yet…​) +which we will ship as `com.evil.apps.supercoolapp`. To do this I need to follow these steps…​ + +#### Step 1: Create the Acme app as usual + +This is pretty strait forward and I’m assuming you all know how to do that…​ + +#### Step 2: Create the Evil Corp Package + +We can just create a new package in the IDE named `com.evil.apps.supercoolapp` and place a main class there. +Ideally it should have the same name as the main class we have in `com.acme.apps.supercoolapp`, I’ll assume they +are both named `Main`. + +The cool thing as that one main can derive functionality from another e.g.: + + + package com.evil.apps.supercoolapp; + public class Main extends com.acme.apps.supercoolapp.Main { + @Override + public void init(Object context) { + super.init(context); + } + + @Override + public void start() { + super.start(); + } + + @Override + public void stop() { + super.stop(); + } + + @Override + public void destroy() { + super.destroy(); + } + } + +Notice that I can just write additional logic in every one of these methods or even replace them entirely to provide +unique functionality for Evil Corp. + +E.g. I can set the theme to a different theme and some common strings from the resource bundle to different values. + +#### Step 3: Run in the Simulator + +The simulator is really just a java class that gets the main class/package as an argument. You can change that +in the project settings under the run section. NetBeans is particularly good with these things as it allows you to define +project configurations and you can switch dynamically between said configurations with just a right click. + +#### Step 4: Build Native App + +Just replace all the references to `com.acme.apps.supercoolapp` with `com.evil.apps.supercoolapp` in the +`codenameone_settings.properties`. You will also need to update the certificates/provisioning information depending +on the customer. Make sure to save the provisioning/certificate data of each customer separately so you don’t get +confused…​ + +You might also want to update the title and other properties within the file. Some developers keep multiple versions +of the file and the application icon and just replace them dynamically with a script. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Nick Koirala** — October 6, 2016 at 1:28 am ([permalink](https://www.codenameone.com/blog/deploy-same-mobile-app-template-multiple-times.html#comment-22560)) + +> Nick Koirala says: +> +> Can you elaborate on how to run in the simulator? I set up a new configuration and put the package/class as the arguments in the run section and it still runs the original Main, not the new Main +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeploy-same-mobile-app-template-multiple-times.html) + + +### **Shai Almog** — October 6, 2016 at 5:22 am ([permalink](https://www.codenameone.com/blog/deploy-same-mobile-app-template-multiple-times.html#comment-22948)) + +> Shai Almog says: +> +> Did you select that configuration as the active one? +> In which IDE? +> Is there output in the console? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeploy-same-mobile-app-template-multiple-times.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/deprecations-simplified-cn1lib-installs-theme-layering.md b/docs/website/content/blog/deprecations-simplified-cn1lib-installs-theme-layering.md new file mode 100644 index 0000000000..9c761934ff --- /dev/null +++ b/docs/website/content/blog/deprecations-simplified-cn1lib-installs-theme-layering.md @@ -0,0 +1,233 @@ +--- +title: Deprecations, Simplified cn1lib installs & Theme Layering +slug: deprecations-simplified-cn1lib-installs-theme-layering +url: /blog/deprecations-simplified-cn1lib-installs-theme-layering/ +original_url: https://www.codenameone.com/blog/deprecations-simplified-cn1lib-installs-theme-layering.html +aliases: +- /blog/deprecations-simplified-cn1lib-installs-theme-layering.html +date: '2015-08-25' +author: Shai Almog +--- + +![Header Image](/blog/deprecations-simplified-cn1lib-installs-theme-layering/ios-cert-wizard-blog-post-header.png) + +#### Deprecations + +We decided to discontinue support for building without a certificate, this support was added initially because +generating an iOS certificate was so difficult and we wanted developers to see that “it works” before committing +to the expense. However, this process is wrought with bugs that are often hard to trace back and error prone. +Added to that is the fact that we now have the new [certificate wizard](/blog/ios-certificate-wizard.html) +which makes the process simpler thus removing the final blocker (no need for a Mac). +We will block this functionality in the build servers by next week and thru the plugin after that. + +We also decided to remove the ability to push with a null device id with the new push servers overhaul. +It was a tough decision to make but I’m sure you will get behind it when +you see the other features we intend to add specifically: delivery reports, status & batched pushes. +We’ll probably restore this functionality in the future in a different form that will allow other features such as +smart segmentations etc. The API will probably take a very different form and be designed for server side +usage. + +Last but not least, we still kept the original web UI that Codename One used in the old appspot server. If you +are still using that UI then it will be discontinued soon! We suggest you migrate to the new web UI in this +website. +If there are features or capabilities missing from the current web UI please let us know. + +#### Build Hints in cn1libs + +Some cn1libs are pretty simple to install, just place them under the lib directory and refresh. However, many of the more +elaborate cn1libs need some pretty complex configurations. This is the case when native code is involved where +we need to add permissions or plist entries for the various native platforms to get everything to work. This makes +the cn1lib’s helpful but less than seamless which is where we want to go. + +If you don’t intend to write a cn1lib you can skip to the next section, for you this post just means that future cn1lib +install instructions would no longer include build hints… However, if you are writing cn1libs then this is a pretty big +new feature… + +We now support two new files that can be placed into the cn1lib root and exist when you create a new library using +the new project wizard: `codenameone_library_required.properties` & `codenameone_library_appended.properties`. + +In these files you can just write a build hint as `codename1.arg.ios.plistInject=...` for the various +hints. The obvious question is why do we need to files? + +There are two types of build hints: required and appended. Required build hints can be something like `ios.objC=true` +which we want to always work. E.g. if a cn1lib defines `ios.objC=true` and another cn1lib defines +`ios.objC=false` things won’t work since one cn1lib won’t get what it needs… +In this case we’d +want the build to fail so we can remove the faulty cn1lib. + +An appended property would be something like `codename1.arg.ios.plistInject=UIBackgroundModesaudio ` +Notice that this can still collide e.g. if a different cn1lib defines its own background mode… However, there are +many valid cases where `ios.plistInject` can be used for other things. In this case we’ll append +the content of the `ios.plistInject` into the build hint if its not already there. + +There are a couple of things you need to keep in mind: + + * This code happens with every “refresh libs” call not dynamically on the server. This means it should be pretty +simple for the developer to investigate issues in this process. + * Changing flags is problematic – there is no “uninstall” process. Since the data is copied into the `codenameone_settings.properties` +file. If you need to change a flag later on you might need to alert users to make changes to their properties essentially +negating the value of this feature… So be very careful when adding properties here. + +The rule of thumb is that a build hint that has a numeric or boolean value is always required. If an entry has a string that you can append with another string +then its probably an appended entry +These build hints are probably of the “required” type: + + + android.debug + android.release + android.installLocation + android.licenseKey + android.stack_size + android.statusbar_hidden + android.googleAdUnitId + android.includeGPlayServices + android.headphoneCallback + android.gpsPermission + android.asyncPaint + android.supportV4 + android.theme + android.cusom_layout1 + android.versionCode + android.captureRecord + android.removeBasePermissions + android.blockExternalStoragePermission + android.min_sdk_version + android.smallScreens + android.streamMode + android.enableProguard + android.targetSDKVersion + android.web_loading_hidden + facebook.appId + ios.keyboardOpen + ios.project_type + ios.newStorageLocation + ios.prerendered_icon + ios.application_exits + ios.themeMode + ios.xcode_version + javascript.inject_proxy + javascript.minifying + javascript.proxy.url + javascript.sourceFilesCopied + javascript.teavm.version + rim.askPermissions + google.adUnitId + ios.includePush + ios.headphoneCallback + ios.enableAutoplayVideo + ios.googleAdUnitId + ios.googleAdUnitIdPadding + ios.enableBadgeClear + ios.locationUsageDescription + ios.bundleVersion + ios.objC + ios.testFlight + desktop.width + desktop.height + desktop.adaptToRetina + desktop.resizable + desktop.fontSizes + desktop.theme + desktop.themeMac + desktop.themeWin + desktop.windowsOutput + noExtraResources + j2me.iconSize + +These build hints should probably be appended + + + android.xapplication + android.xpermissions + android.xintent_filter + android.facebook_permissions + android.stringsXml + android.style + android.nonconsumable + android.xapplication_attr + android.xactivity + android.pushVibratePattern + android.proguardKeep + android.sharedUserId + android.sharedUserLabel + ios.urlScheme + ios.interface_orientation + ios.plistInject + ios.facebook_permissions + ios.applicationDidEnterBackground + ios.viewDidLoad + ios.glAppDelegateHeader + ios.glAppDelegateBody + ios.beforeFinishLaunching + ios.afterFinishLaunching + ios.add_libs + +#### Theme Layering + +Theme layering is something that comes up often in support queries and we don’t have a good reference for it +so I decided to write a quick tutorial on that. +There are two use cases in which you would want to use layering: + + 1. You want a **slightly** different theme in one platform + 2. You want the ability to customize your theme for a specific use case, e.g. let a user select larger fonts + +This is actually pretty easy to do and doesn’t require re-doing the entire theme. You can do something very similar +to the cascading effect of CSS where a theme is applied “on top” of another theme. To do that just add a new +theme, make sure to remove the include native theme constant in the new theme. Then in the new theme define +the changes e.g. if you just want a larger default font define only that property for all the relevant UIID’s and ignore +all other properties! + +For a non-gui builder app the theme loading looks like this: + + + public void init(Object context) { + try { + theme = Resources.openLayered("/theme"); + UIManager.getInstance().setThemeProps(theme.getTheme(theme.getThemeResourceNames()[0])); + } catch (IOException e) { + e.printStackTrace(); + } + } + +Or for newer apps like this: + + + theme = UIManager.initFirstTheme("/theme"); + +You should fix it to look like this: + + + theme = UIManager.initNamedTheme("/theme", "Theme"); + +Notice, this assumes the name of your main theme is “Theme” (not the layer theme you just added). This is important +since the original code relies on the theme being in the 0 position in the theme name array which might not be +the case! +Then when you want to add a layer just use: + + + UIManager.getInstance().addThemeProps(theme.getTheme("NameOfLayerTheme")); + +The `addThemeProps` call will layer the secondary theme on top of the primary “Theme” and +keep the original UIID’s defined in “Theme” intact. + +For a GUI builder app this is just as simple, you can override the initTheme method in the state machine in +exactly the same way to specify the theme name explicitly: + + + protected void initTheme(Resources res) { + UIManager.getInstance().setThemeProps(res.getTheme("Theme")); + } + +Then use the `addThemeProps` anywhere you want, notice that you can just get the theme using +`fetchResourceFile()` in the state machine. + +If you apply theme changes to a running application you can use `Form`‘s `refreshTheme()` +to update the UI instantly and provide visual feedback for the theme changes. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/desktop-skin.md b/docs/website/content/blog/desktop-skin.md new file mode 100644 index 0000000000..11c5be8144 --- /dev/null +++ b/docs/website/content/blog/desktop-skin.md @@ -0,0 +1,73 @@ +--- +title: Desktop Skin +slug: desktop-skin +url: /blog/desktop-skin/ +original_url: https://www.codenameone.com/blog/desktop-skin.html +aliases: +- /blog/desktop-skin.html +date: '2017-07-03' +author: Shai Almog +--- + +![Header Image](/blog/desktop-skin/new-features-4.jpg) + +During the final stages of the 3.7 release cycle we had a lot of material to go thru and Chen slipped a couple of features that we just didn’t have the time to discuss. One of those features is the new desktop skin which is a special case skin to debug desktop and JavaScript apps. + +Unlike other skins it doesn’t scale, it resizes the UI when you resize it. It has no skin decorations except for a small bar at the bottom that indicates the current resolution. You can use this to simulate resizing from the user. + +![Activate the desktop skin thru the skins menu](/blog/desktop-skin/desktop-skin-menu.png) + +Figure 1. Activate the desktop skin thru the skins menu + +![The desktop skin running the kitchen sink demo](/blog/desktop-skin/desktop-skin-running.png) + +Figure 2. The desktop skin running the kitchen sink demo + +### Desktop Features + +We’ve been moving slowly to improve Codename Ones desktop support. Our own tools are already mostly written using Codename One (GUI builder, Settings). + +We already feel that using Codename One in a desktop setting can produce a decent result in the right hands and we know a few people do exactly that. However, it’s hard for us to gauge expectations and desires from customers without feedback. When we build our own apps we use a lot of tricks we never bother to publish as our use cases are usually edge cases. + +If you are looking to build desktop and web apps using Codename One let us know and we can discuss features that would make it better suited for those use cases. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Carlos** — July 4, 2017 at 6:53 pm ([permalink](https://www.codenameone.com/blog/desktop-skin.html#comment-23359)) + +> Good move. +> +> Is it possible to programmatically set the size of the window at startup? That is something that I’m missing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdesktop-skin.html) + + +### **Shai Almog** — July 5, 2017 at 4:10 am ([permalink](https://www.codenameone.com/blog/desktop-skin.html#comment-23652)) + +> Thanks. +> Not at this time, we have the desktop.width and desktop.height build hints but not programmatically. +> +> You can use a native interface and just fine the JFrame then resize that using Swing code. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdesktop-skin.html) + + +### **Gareth Murfin** — February 14, 2018 at 9:03 am ([permalink](https://www.codenameone.com/blog/desktop-skin.html#comment-23723)) + +> Gareth Murfin says: +> +> I love the desktop skin, it would definitely be great if when you resized it then remembered the size for next time, this skin makes the emulator very usable I think, and would be far cooler if it would remember resize too. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdesktop-skin.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/desktop-vision-mobile-misc-changes.md b/docs/website/content/blog/desktop-vision-mobile-misc-changes.md new file mode 100644 index 0000000000..1dbac802dd --- /dev/null +++ b/docs/website/content/blog/desktop-vision-mobile-misc-changes.md @@ -0,0 +1,126 @@ +--- +title: Desktop, Vision Mobile & Misc Changes +slug: desktop-vision-mobile-misc-changes +url: /blog/desktop-vision-mobile-misc-changes/ +original_url: https://www.codenameone.com/blog/desktop-vision-mobile-misc-changes.html +aliases: +- /blog/desktop-vision-mobile-misc-changes.html +date: '2014-02-04' +author: Shai Almog +--- + +![Header Image](/blog/desktop-vision-mobile-misc-changes/desktop-vision-mobile-misc-changes-1.png) + + + + + +![Picture](/blog/desktop-vision-mobile-misc-changes/desktop-vision-mobile-misc-changes-1.png) + + + + +Vision mobile just released their new developer economics study, you can check it out +[ +here +](http://www.visionmobile.com/DE1Q14CodenameOne) +. + + + + + + + + +We toggled the +[ +new pipeline mode +](http://www.codenameone.com/3/post/2014/02/a-new-pipeline-for-windows-phone.html) +for windows + +phone to be the default, its clearly the way to go forward in the long run since we just don’t have any other choice. All feedback on the new pipeline found it to improve performance significantly and generally reduces some of the paint issues that we run into with Windows Phone. However, there are a couple of reports pointing out that font quality has degraded with the new pipeline. We are looking into this but came to the decision that even if this isn’t solvable we will stick with the new pipeline since the old one is just not viable for moving forward. + + + + + +As part of our ongoing work with the new Android pipeline we added an experimental rendering mode that tries to automatically detect invisible layers and not draw them. You can enable this mode by invoking + +Display.getInstance().setProperty(“blockOverdraw”, “true”); + + +This might improve performance for some cases and might improve performance on platforms other than Android. We’d be interested to hear if this mode break stuff in your application. + + + + +** +Desktop Build Arguments +** + + + + + +Our recent desktop build support allows pro users to send builds for desktop applications. These builds are actually highly customizable using the following build arguments: + +desktop.width – width of the window in pixels (defaults to 800) + + +desktop.height – height of the window in pixels + + + +(defaults to 800) + + +desktop.fullScreen – whether the application will run in full screen + +(true/false defaults to false) + + +desktop.adaptToRetina – doubles the pixels for a high resolution display (true/false defaults to true) + + +desktop.resizable – whether the window would be resizable (true/false defaults to true) + + +desktop.theme – the theme to use as the native theme defaults to “native”. Can be “none” to indicate no theme or the name of any resource file within the bundle that you would like to use as a base without the .res extension. E.g. iPhoneTheme assuming you placed the iPhoneTheme.res file in your src directory. + + + +desktop.windowsOutput – the installer type you want for Windows can be exe or msi defaults to msi + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — February 6, 2014 at 6:04 am ([permalink](https://www.codenameone.com/blog/desktop-vision-mobile-misc-changes.html#comment-21846)) + +> Anonymous says: +> +> Display.getInstance().setProperty(“blockOverdraw”, “true”); doesn’t seem to break anything on first sight. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdesktop-vision-mobile-misc-changes.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/detect-edt-violations.md b/docs/website/content/blog/detect-edt-violations.md new file mode 100644 index 0000000000..d647ae25c0 --- /dev/null +++ b/docs/website/content/blog/detect-edt-violations.md @@ -0,0 +1,42 @@ +--- +title: Detect EDT Violations +slug: detect-edt-violations +url: /blog/detect-edt-violations/ +original_url: https://www.codenameone.com/blog/detect-edt-violations.html +aliases: +- /blog/detect-edt-violations.html +date: '2012-10-30' +author: Shai Almog +--- + +![Header Image](/blog/detect-edt-violations/detect-edt-violations-1.png) + + + + +[ +![Picture](/blog/detect-edt-violations/detect-edt-violations-1.png) +](/img/blog/old_posts/detect-edt-violations-large-2.png) + +One of the hardest ideas for developers to grasp in Codename One (or GUI programming in general) is the idea of a single event dispatch thread (EDT). The rules of using it and releasing it are sometimes complex and mistakes are very easy to make e.g.: + + * Writing complex/slow code that blocks the EDT thus slowing the entire application + * Accessing Codename One widgets from a thread that isn’t the EDT. + +The problem is that both of these issues are notoriously hard to catch on the simulator but often crop up on the device where race conditions can happen more easily and slow EDT performance is more noticeable. + +To ease the process of detecting these violations we added a flag to the simulator allowing you to receive information about such cases. When using light debugging you will see printouts to the console when accessing the EDT from a separate thread or taking too long to perform the task on the EDT. When setting it to full you will also see the stack trace where the violation was detected. + +These tools aren’t perfect and they sometimes printout warnings that are unwarranted while entirely missing a real violation. However they can be a valuable tool in improving your application’s portability and responsiveness on multiple devices when used consciously. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system.md b/docs/website/content/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system.md new file mode 100644 index 0000000000..09bade9d19 --- /dev/null +++ b/docs/website/content/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system.md @@ -0,0 +1,241 @@ +--- +title: Developer Promotion – practical guide & statistics about the Java ecosystem +slug: developer-promotion-practical-guide-statistics-about-the-java-echo-system +url: /blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system/ +original_url: https://www.codenameone.com/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system.html +aliases: +- /blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system.html +date: '2014-07-08' +author: Shai Almog +--- + +![Header Image](/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system/developer-promotion-practical-guide-statistics-about-the-java-echo-system-1.png) + + + + +[ +![Picture](/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system/developer-promotion-practical-guide-statistics-about-the-java-echo-system-1.png) +](/img/blog/old_posts/developer-promotion-practical-guide-statistics-about-the-java-echo-system-large-7.png) + + + +Before we launched our +[ +recent promotion +](http://www.codenameone.com/blog/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300) +for JavaOne tickets with +[ +Java Code Geeks +](http://javacodegeeks.com/) +we sought out guides/tutorials about running such a promotion, unfortunately we didn’t find anything useful so we had to improvise and work by instinct. This post will also cover some of the statistical results about the Java community so if this is the reason you are reading this post skip down for some interesting takeaways. + +** +Running a promotion tips & tricks +** + +The idea started when one of our talks got accepted to JavaOne, suddenly we had two extra tickets (we got 3 tickets with the booth) so we could give away two tickets. From our experience we came to the conclusion that most developers don’t know about Codename One yet and that is probably the most important thing we need to improve in our outreach. So here are a few conclusions we came to in no particular order: + +1\. We need a partner to handle the giveaway – this removed the bias from us. We have an incentive to give the tickets to our best customers so we can’t really be fair. That’s why we picked +[ +Java Code Geeks +](http://javacodegeeks.com/) +. + +2\. We picked +[ +Java Code Geeks +](http://javacodegeeks.com/) +as a partner – we needed a partner who is focused on Java (check), who has a big enough audience (check), whose audience isn’t already familiar with our product (check). This is probably the most important step, most of our contestant came from Java Code Geeks and as you can see from the chart to the right. Most of the people who entered our contest didn’t know about Codename One in advance and were happy to find out about us. + +3\. We created incentives to social share – most of the people who would read +[ +Java Code Geeks +](http://javacodegeeks.com/) +are probably up to date with the latest technology, but their friends (and friends of friends) might not be. The true value of the promotion is social share which is why we made the contest require sharing. Initially we wanted the person with the most retweets/shares to “win” but +[ +Byron from Java Code Geeks +](http://www.javacodegeeks.com/author/Byron-Kiourtzoglou/) +objected to this approach (in hindsight I think he was right to object) claiming that it would rule out people who don’t have many friends. It would also have promoted cheating which is a huge problem. + +4\. We created very detailed rules for the competition – yes, most people didn’t read them (as is obvious by some of the submissions we got) but there are now rules that the raffle itself should follow. We used Google docs to collect details and signups which allowed us to collect a lot of structured data. + +We included an entirely optional survey and 99% of submitters answered questions within the survey despite the optionality! + +5\. We promoted the giveaway in our respective newsletters which is usually the most effective way to get people to signup. However, a single retweet by @java is probably more valuable than an 18k strong mailing list. + +6\. We used Facebook, Twitter and adsense ads – all charged us and delivered literally nothing. Facebook charged for clicks that Google Analytics didn’t show. Normally I would chuck this as a Google analytics omission however we saw a lot of clicks on the Facebook side and no submissions to the contest form… This seems to indicate that Facebook is charging for fraudulent clicks! + +* * * + +## Results + + + + + +[ +![Picture](/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system/developer-promotion-practical-guide-statistics-about-the-java-echo-system-2.png) +](/img/blog/old_posts/developer-promotion-practical-guide-statistics-about-the-java-echo-system-large-8.png) + + + +We asked developers which operating system they were using and were pretty shocked by the results. We see Macs all over JavaOne and all the conferences I go to, but it seems that Macs are a minority to Linux! + +* * * + + + + +[ +![Picture](/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system/developer-promotion-practical-guide-statistics-about-the-java-echo-system-3.png) +](/img/blog/old_posts/developer-promotion-practical-guide-statistics-about-the-java-echo-system-large-9.png) + + + +The IDE of choice brought a pretty predictable result although much closer than we would have thought as the number of answers grew the distance between the IDE’s grew as well with NetBeans surpassing IDEA and Eclipse growing in strength. However, the race between the IDE’s is still very real and despite Eclipse lead its position seems very assailable in the market. Our decision to support all 3 IDE’s seems like an excellent decision in this light. + +* * * + + + + +[ +![Picture](/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system/developer-promotion-practical-guide-statistics-about-the-java-echo-system-4.png) +](/img/blog/old_posts/developer-promotion-practical-guide-statistics-about-the-java-echo-system-large-10.png) + + + +Another shocker is the Java platform of choice. I always get the sense that all developers working with Java have migrated to Java EE. This doesn’t seem to be the case entirely, there are plenty of developers still working with Java SE. I’m actually surprised there are still 10% of developers that are working on Java ME. + +* * * + + + + +[ +![Picture](/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system/developer-promotion-practical-guide-statistics-about-the-java-echo-system-5.png) +](/img/blog/old_posts/developer-promotion-practical-guide-statistics-about-the-java-echo-system-large-11.png) + + + +What is your preferred Java news source, here we excluded Java Code Geeks since we assumed unreasonable bias in the results (according to other stats it would probably occupy well over 50%). Notice that while some outlets (e.g. dzone) are clearly dominant there is no true leader. When targeting the Java community we literally need to be everywhere. + +* * * + + + + +[ +![Picture](/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system/developer-promotion-practical-guide-statistics-about-the-java-echo-system-6.png) +](/img/blog/old_posts/developer-promotion-practical-guide-statistics-about-the-java-echo-system-large-12.png) + + + +Do Java developers use other languages besides Java? + + +Honestly we should have asked what for? JavaScript/CoffeScript took the lead but do developers use it for HTML or do they use server JavaScript e.g. NodeJS? + + + +The main motivation behind asking this question was potential support for other languages in Codename One especially JVM languages e.g. JRuby, Scala etc. + + +We probably should have phrased a few different questions to get refined answers. + +* * * + +## Final thoughts + + +I hope you found these results useful and illuminating. For the next contest/survey we will run we picked up the following lessons: + +1\. Better limits on the goals of the question – e.g. with the languages besides Java we didn’t quite get an answer. I would probably ask, are you interested in other languages? Would you prefer another language? + +2\. We would not waste a cent on Advertising. + +3\. Partner selection is critical – Java Code Geeks delivered! + +4\. As pleased as we were with the work done by the guys at Java Code Geeks, it was crucial for us to come prepared. We phrased the contest terms and defined most of the conditions/questions. Your partner can be very helpful but only you can define your own expectations and results. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — July 10, 2014 at 5:30 am ([permalink](https://www.codenameone.com/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system.html#comment-21886)) + +> Anonymous says: +> +> From the company where I am working, they analyzed many mobile cross platform development tools. The assessors know your product, but one of the biggest critiques on your product is they experience more inconsistency and adjusting for cross platforms, especially Windows and BB 10 where there are some growing demand from our clients. So instead, they opted for other tools which offers more consistency and fortunately is also favorable with our development team’s programming expertise. They don’t think your tool is bad, just more inconsistent and tedious to use than some of the others they have tried. Perhaps its not just that people don’t know CodenameOne, but also run into the issues we also encountered and therefore not using it and would rather invest in expertise for other tools? Anyway its just an honest opinion and suggestion from what I observed from our team and perhaps we are the only few. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeveloper-promotion-practical-guide-statistics-about-the-java-echo-system.html) + + +### **Anonymous** — July 10, 2014 at 6:35 am ([permalink](https://www.codenameone.com/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system.html#comment-22059)) + +> Anonymous says: +> +> Thanks for the feedback, I’d really like to know more about the evaluation and whether the person responsible had any contact with us. +> +> One point I’d like to clarify is that we know for a fact that our reach is to blame. Since our product is cloud based we can “see” the retention statistics rather easily and they exceed industry standards. The chart above showing the number of people who haven’t heard about Codename One in a survey directed at our community as well is a pretty strong indicator of that fact. +> +> About Windows Phone and BB10 you do have a point. We have a couple of users to whom BB10 is a target and they found the Android bridge to be sufficient. I’m not aware of any major company in our field doing native BB10 development, it doesn’t seem viable with the Android support. +> +> The Windows Phone port is a disappointment to us as well. There are technical difficulties due to very poor architectural decisions made by the developers at MS and after 3-4 different rewrites we aren’t much better off. I’m not aware of any cross platform tool that works well with Windows Phone, Cordova (HTML5) is bearable with its obvious caveats. Hopefully we will able to take a shortcut there as well: [http://gigaom.com/2014/07/0…]() +> +> I’m not sure I understand the other comment related to the option you eventually took but we’d be happy if you raise some of the issues you’ve experienced in the discussion forum. Even if we don’t have an answer or can’t improve something good feedback is how we improve the product. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeveloper-promotion-practical-guide-statistics-about-the-java-echo-system.html) + + +### **Anonymous** — July 10, 2014 at 7:32 am ([permalink](https://www.codenameone.com/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system.html#comment-22196)) + +> Anonymous says: +> +> The team decided develop webapps for now, but is busy assessing whether to just hire skills for specific platforms for native development in the future. Since there are many top apps developed for Windows Phone, why is CodenameOne having difficulty? Is it better to develop apps for Windows Phone from scratch reusing some of the source done by CodenameOne? Are you still planning to improve Windows support? Anyway, I’ll have a word with the assessors and see if they want to describe the issues they are having in your forum, but it seems its all about getting the product out on time for now. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeveloper-promotion-practical-guide-statistics-about-the-java-echo-system.html) + + +### **Anonymous** — July 10, 2014 at 11:17 am ([permalink](https://www.codenameone.com/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system.html#comment-24183)) + +> Anonymous says: +> +> I explained some of the issues we had with Windows Phone here: [http://www.codenameone.com/…]() +> +> It helps to understand how Codename One works and why its so portable [http://www.codenameone.com/…]() +> +> We’d love to have a better Windows Phone port, we already invested into 3 rewrites attempting to improve the situation. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeveloper-promotion-practical-guide-statistics-about-the-java-echo-system.html) + + +### **Anonymous** — July 10, 2014 at 12:40 pm ([permalink](https://www.codenameone.com/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system.html#comment-22028)) + +> Anonymous says: +> +> One of the product our assessors looked at is called: Xamarin ([www.xamarin.com]()), which is similar in concept to yours except the development code is done in C# and not Java. The downside is our development team is not C# centric, but it looks promising for people that are. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeveloper-promotion-practical-guide-statistics-about-the-java-echo-system.html) + + +### **Anonymous** — July 11, 2014 at 1:34 am ([permalink](https://www.codenameone.com/blog/developer-promotion-practical-guide-statistics-about-the-java-echo-system.html#comment-22131)) + +> Anonymous says: +> +> Xamarin isn’t a Write Once Run Anywhere solution. It effectively allows you to write your application in C# but you invoke native device API’s. This means you have some common business logic but your UI (roughly 50% of the code) would be platform specific. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdeveloper-promotion-practical-guide-statistics-about-the-java-echo-system.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/device-bugs-and-updates.md b/docs/website/content/blog/device-bugs-and-updates.md new file mode 100644 index 0000000000..3c80427448 --- /dev/null +++ b/docs/website/content/blog/device-bugs-and-updates.md @@ -0,0 +1,57 @@ +--- +title: Device Bugs And Updates +slug: device-bugs-and-updates +url: /blog/device-bugs-and-updates/ +original_url: https://www.codenameone.com/blog/device-bugs-and-updates.html +aliases: +- /blog/device-bugs-and-updates.html +date: '2014-02-17' +author: Shai Almog +--- + +![Header Image](/blog/device-bugs-and-updates/device-bugs-and-updates-1.png) + + + + + +![Picture](/blog/device-bugs-and-updates/device-bugs-and-updates-1.png) + + + + +We’ve been even more busy than usual with our first +[ +corporate deployment +](/corporate-server.html) +kicking off, this is currently a pretty rough process that requires a lot of hands on help from us but we hope to make it less painful for our customers. Either way, this being a completely new offering with a great deal of complexity involved its an uphill effort which is part of why we are experiencing a slowdown in new features. + + + + +Another aspect that hit us this week is the camera bug on iOS which apparently still wasn’t resolved, it got solved thanks to the combined stubbornness of Chen and some clues from Steve. We also had some rendering artifacts on Android KitKat due to regressions Android has with its TextureView, we ended up disabling the TextureView which we introduced to workaround a relatively rare Android bug (there are a lot of those around). You can still explicitly enable the TextureView approach by using the build flag android.textureView=true. + + + + +These issues are highlighting the importance of migrating to the Android async mode, unfortunately it isn’t complete at this time and it too suffers from some significant issues. + + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/device-tester.md b/docs/website/content/blog/device-tester.md new file mode 100644 index 0000000000..10fa90c7c2 --- /dev/null +++ b/docs/website/content/blog/device-tester.md @@ -0,0 +1,292 @@ +--- +title: Device Tester +slug: device-tester +url: /blog/device-tester/ +original_url: https://www.codenameone.com/blog/device-tester.html +aliases: +- /blog/device-tester.html +date: '2016-07-04' +author: Shai Almog +--- + +![Header Image](/blog/device-tester/device-tester.png) + +A common issue we get from developers relates to minor differences between devices which are often very +hard to quantify. They are also very hard to explain to the developers in some occasions. One of the biggest +points of difficulty is density which is a very hard concept to grasp and it’s often hard to know which image will +be used from the set of multi images or how many pixels will be used for 1 millimeter. + +To make this process slightly easier we created a new demo that is remarkably simple but we are hoping it +would also be remarkably helpful. It just prints on the screen the settings and values of all the important +details mostly from the [Display class](https://www.codenameone.com/javadoc/com/codename1/ui/Display.html). + +This demo also allows you to send the details to your email directly so you can send it to a user who is experiencing +issues and understand some things about their device. This will also make it simpler for you to communicate issues +with us as we won’t need as much back and forth with device details. + +You can check out the full repository on github [here](https://github.com/codenameone/DeviceTester) and you can +use that to get proper debug logic for your app. We hope to add it to the IDE’s so it will be a part of the new app +wizard dialog. + +My OnePlus One outputs something like this, which you can see is pretty useful if you want to understand the device +type we are dealing with: + + + Density: DENSITY_HD + Platform Name: and + User Agent: Dalvik/2.1.0 (Linux; U; Android 6.0.1; A0001 Build/MMB29X) + OS:Android + OS Version: 6.0.1 + UDID:865800025623619 + MSISDN: + Display Width X Height: 1080X1920 + 1mm In Pixels: 18.898 + Language: en + Locale: US + Currency Symbol: $ + Are Mutable Images Fast: false + Can Dial: true + Can Force Orientation: true + Has Camera: true + Badging: false + Desktop: false + Tablet: false + Gaussian Blur Support: true + Get All Contacts Fast: true + Multi Touch: true + PICKER_TYPE_DATE: true + PICKER_TYPE_DATE_AND_TIME: false + PICKER_TYPE_STRINGS: true + PICKER_TYPE_TIME: true + Native Share: true + Native Video Player Controls: true + Notification: true + Open Native Navigation: true + Screen Saver Disable: true + Simulator: false + +The Java code to produce this is pretty trivial albeit a bit verbose: + + + public void start() { + if(current != null){ + current.show(); + return; + } + Form hi = new Form("Basic Details", BoxLayout.y()); + Display d = Display.getInstance(); + String density = ""; + switch(Display.getInstance().getDeviceDensity()) { + case Display.DENSITY_2HD: + density = "DENSITY_2HD"; + break; + case Display.DENSITY_4K: + density = "DENSITY_4K"; + break; + case Display.DENSITY_560: + density = "DENSITY_560"; + break; + case Display.DENSITY_HD: + density = "DENSITY_HD"; + break; + case Display.DENSITY_HIGH: + density = "DENSITY_HIGH"; + break; + case Display.DENSITY_LOW: + density = "DENSITY_LOW"; + break; + case Display.DENSITY_MEDIUM: + density = "DENSITY_MEDIUM"; + break; + case Display.DENSITY_VERY_HIGH: + density = "DENSITY_VERY_HIGH"; + break; + case Display.DENSITY_VERY_LOW: + density = "DENSITY_VERY_LOW"; + break; + } + + double pixelsPerMM = (((double)d.convertToPixels(1000)) / 1000.0); + L10NManager l10n = L10NManager.getInstance(); + + hi.add("Density:"). + add(new SpanLabel(density)). + add(" "). + add("Platform Name:"). + add(new SpanLabel(d.getPlatformName())). + add(" "). + add("User Agent:"). + add(new SpanLabel(d.getProperty("User-Agent", ""))). + add(" "). + add("OS:"). + add(new SpanLabel(d.getProperty("OS", ""))). + add(" "). + add("OS Version:"). + add(new SpanLabel(d.getProperty("OSVer", ""))). + add(" "). + add("UDID:"). + add(new SpanLabel(d.getUdid())). + add(" "). + add("MSISDN:"). + add(new SpanLabel(d.getMsisdn())). + add(" "). + add("Display Width X Height:"). + add(new SpanLabel(d.getDisplayWidth() + "X" + d.getDisplayHeight())). + add(" "). + add("1mm In Pixels:"). + add(new SpanLabel(l10n.format(pixelsPerMM))). + add(" "). + add("Language:"). + add(new SpanLabel(l10n.getLanguage())). + add(" "). + add("Locale:"). + add(new SpanLabel(l10n.getLocale())). + add(" "). + add("Currency Symbol:"). + add(new SpanLabel(l10n.getCurrencySymbol())). + add(" "). + add(uneditableCheck("Are Mutable Images Fast", d.areMutableImagesFast())). + add(uneditableCheck("Can Dial", d.canDial())). + add(uneditableCheck("Can Force Orientation", d.canForceOrientation())). + add(uneditableCheck("Has Camera", d.hasCamera())). + add(uneditableCheck("Badging", d.isBadgingSupported())). + add(uneditableCheck("Desktop", d.isDesktop())). + add(uneditableCheck("Tablet", d.isTablet())). + add(uneditableCheck("Gaussian Blur Support", d.isGaussianBlurSupported())). + add(uneditableCheck("Get All Contacts Fast", d.isGetAllContactsFast())). + add(uneditableCheck("Multi Touch", d.isMultiTouch())). + add(uneditableCheck("PICKER_TYPE_DATE", d.isNativePickerTypeSupported(Display.PICKER_TYPE_DATE))). + add(uneditableCheck("PICKER_TYPE_DATE_AND_TIME", d.isNativePickerTypeSupported(Display.PICKER_TYPE_DATE_AND_TIME))). + add(uneditableCheck("PICKER_TYPE_STRINGS", d.isNativePickerTypeSupported(Display.PICKER_TYPE_STRINGS))). + add(uneditableCheck("PICKER_TYPE_TIME", d.isNativePickerTypeSupported(Display.PICKER_TYPE_TIME))). + add(uneditableCheck("Native Share", d.isNativeShareSupported())). + add(uneditableCheck("Native Video Player Controls", d.isNativeVideoPlayerControlsIncluded())). + add(uneditableCheck("Notification", d.isNotificationSupported())). + add(uneditableCheck("Open Native Navigation", d.isOpenNativeNavigationAppSupported())). + add(uneditableCheck("Screen Saver Disable", d.isScreenSaverDisableSupported())). + add(uneditableCheck("Simulator", d.isSimulator())); + + final String densityStr = density; + hi.getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_SEND, e -> { + StringBuilder body = new StringBuilder("Density: "). + append(densityStr). + append("n"). + append("Platform Name: "). + append(d.getPlatformName()). + append("n"). + append("User Agent: "). + append(d.getProperty("User-Agent", "")). + append("n"). + append("OS: "). + append(d.getProperty("OS", "")). + append("n"). + append("OS Version: "). + append(d.getProperty("OSVer", "")). + append("n"). + append("UDID: "). + append(d.getUdid()). + append("n"). + append("MSISDN: "). + append(d.getMsisdn()). + append("n"). + append("Display Width X Height: "). + append(d.getDisplayWidth()).append("X").append(d.getDisplayHeight()). + append("n"). + append("1mm In Pixels: "). + append(l10n.format(pixelsPerMM)). + append("n"). + append("Language: "). + append(l10n.getLanguage()). + append("n"). + append("Locale: "). + append(l10n.getLocale()). + append("n"). + append("Currency Symbol: "). + append(l10n.getCurrencySymbol()). + append("nAre Mutable Images Fast: "). + append(d.areMutableImagesFast()). + append("nCan Dial: "). + append(d.canDial()). + append("nCan Force Orientation: ").append(d.canForceOrientation()). + append("nHas Camera: ").append(d.hasCamera()). + append("nBadging: ").append(d.isBadgingSupported()). + append("nDesktop: ").append(d.isDesktop()). + append("nTablet: ").append(d.isTablet()). + append("nGaussian Blur Support: ").append(d.isGaussianBlurSupported()). + append("nGet All Contacts Fast: ").append(d.isGetAllContactsFast()). + append("nMulti Touch: ").append(d.isMultiTouch()). + append("nPICKER_TYPE_DATE: ").append(d.isNativePickerTypeSupported(Display.PICKER_TYPE_DATE)). + append("nPICKER_TYPE_DATE_AND_TIME: ").append(d.isNativePickerTypeSupported(Display.PICKER_TYPE_DATE_AND_TIME)). + append("nPICKER_TYPE_STRINGS: ").append(d.isNativePickerTypeSupported(Display.PICKER_TYPE_STRINGS)). + append("nPICKER_TYPE_TIME: ").append(d.isNativePickerTypeSupported(Display.PICKER_TYPE_TIME)). + append("nNative Share: ").append(d.isNativeShareSupported()). + append("nNative Video Player Controls: ").append(d.isNativeVideoPlayerControlsIncluded()). + append("nNotification: ").append(d.isNotificationSupported()). + append("nOpen Native Navigation: ").append(d.isOpenNativeNavigationAppSupported()). + append("nScreen Saver Disable: ").append(d.isScreenSaverDisableSupported()). + append("nSimulator: ").append(d.isSimulator()); + + Message msg = new Message(body.toString()); + + Display.getInstance().sendMessage(new String[] { Display.getInstance().getProperty("built_by_user", "[[email protected]](/cdn-cgi/l/email-protection)") }, + "Device Details", msg); + }); + + hi.show(); + } + + private CheckBox uneditableCheck(String t, boolean v) { + CheckBox c = new CheckBox(t); + c.setSelected(v); + c.setEnabled(false); + return c; + } +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — July 5, 2016 at 11:02 pm ([permalink](https://www.codenameone.com/blog/device-tester.html#comment-22885)) + +> bryan says: +> +> Very useful – thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdevice-tester.html) + + +### **bryan** — July 5, 2016 at 11:54 pm ([permalink](https://www.codenameone.com/blog/device-tester.html#comment-21515)) + +> bryan says: +> +> as per issue 1808, Display.getInstance().sendMessage() doesn’t work on WP10. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdevice-tester.html) + + +### **Imriel** — July 12, 2016 at 5:59 am ([permalink](https://www.codenameone.com/blog/device-tester.html#comment-22625)) + +> Imriel says: +> +> How to check with device memory? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdevice-tester.html) + + +### **Shai Almog** — July 13, 2016 at 3:54 am ([permalink](https://www.codenameone.com/blog/device-tester.html#comment-22634)) + +> Shai Almog says: +> +> You can’t do that reliably. Devices have a mixed notion of memory segmentation and we don’t really know the available memory in some cases. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdevice-tester.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/diagonal-badging.md b/docs/website/content/blog/diagonal-badging.md new file mode 100644 index 0000000000..192d1da5fa --- /dev/null +++ b/docs/website/content/blog/diagonal-badging.md @@ -0,0 +1,116 @@ +--- +title: Diagonal Badging +slug: diagonal-badging +url: /blog/diagonal-badging/ +original_url: https://www.codenameone.com/blog/diagonal-badging.html +aliases: +- /blog/diagonal-badging.html +date: '2020-07-09' +author: Shai Almog +--- + +![Header Image](/blog/diagonal-badging/learn-codenameone-2.jpg) + +Recently I got a [question on stackoverflow](https://stackoverflow.com/questions/62639544/codename-one-how-to-design-an-inverted-status-badge/62669046) about doing a diagonal badge that’s actually quite similar to the one on our website. This isn’t hard to do in Codename One but it requires a bit of tinkering so here’s how you would implement that. + +As a matter of fact the original code I provided in the answer had a bit of a misbehavior which I’m fixing for this blog post so everything will look correct: + + + Form hi = new Form("Hi World", BoxLayout.y()); + + // just filling some space so the layer below will be visible + SpanLabel base = new SpanLabel("Hi World,nLorem IpsumnLorem IpsumnLorem IpsumnLorem IpsumnLorem IpsumnLorem IpsumnLorem IpsumnLorem IpsumnLorem IpsumnLorem Ipsumn"); + + // this is the green label + Label green = new Label("Green Stuff") { + private int actualHeight = 10; + + // we ask for more space so when we rotate the label it won't be clipped out + @Override + protected Dimension calcPreferredSize() { + Dimension d = super.calcPreferredSize(); + + // since we asked for more space the background will become a sqare + // we don't want that so we save the "real" height here + actualHeight = d.getHeight(); + d.setHeight(d.getWidth()); + return d; + } + + @Override + public void paint(Graphics g) { + // I move the drawing context up and to the left otherwise + // the banner will be cropped on the corner and look odd + g.translate(-(actualHeight / 2), -(actualHeight / 2)); __**(1)** + + // we rotate by 45 degrees in radians around the pivot point + // which is the center of the component + g.rotateRadians((float)(-Math.PI / 4.0), + getX() + getWidth() / 2, + getY() + getHeight() / 2); + + // we save the old color and set a background color then + // draw the background manually + int c = g.getColor(); + g.setColor(0xff00); + + // we take extra space so the banner will stretch further + // I use fill here but I can use draw image if I have an + // image from the designer that looks better + g.fillRect(getX() - 50, + getY() + getHeight() / 2 - actualHeight / 2, + getWidth() + 100, actualHeight); + + // we let the label draw its content + super.paint(g); + + // restoring the graphics context to the original value + g.setColor(c); + g.resetAffine(); + } + }; + + // we're drawing the background manually so we must make it transparent + Style s = green.getUnselectedStyle(); + s.setBgTransparency(0); + + // I want extra side padding because the rotation will cause the sides + // to crop so the text needs to be in the center + s.setPaddingUnit(Style.UNIT_TYPE_DIPS); __**(2)** + s.setPadding(1, 1, 3, 3); + + // we're layering the component on top of one another. The green + // label is positioned in the top left coordinate. + Container cnt = LayeredLayout.encloseIn(base, + FlowLayout.encloseIn(green)); + hi.add(cnt); + + hi.show(); + +__**1** | The original post was missing this line to move the context up and to the left +---|--- +__**2** | It was also missing these two lines + +So this is what we see in the new code: + +![The Correct Banner](/blog/diagonal-badging/green-banner.png) + +Figure 1. The Correct Banner + +But the older code cropped things badly causing an arrow effect: + +![The Arrow Effect](/blog/diagonal-badging/green-banner-arrow.png) + +Figure 2. The Arrow Effect + +What we see here is the banner being drawn at the edge of the component bounds. As a result the component bounds crop it on the right and bottom producing an arrow. + +Moving the drawing a bit up and to the left makes sure we reach the edge at just the right place. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/different-icons.md b/docs/website/content/blog/different-icons.md new file mode 100644 index 0000000000..d6b078565c --- /dev/null +++ b/docs/website/content/blog/different-icons.md @@ -0,0 +1,98 @@ +--- +title: Different Icons +slug: different-icons +url: /blog/different-icons/ +original_url: https://www.codenameone.com/blog/different-icons.html +aliases: +- /blog/different-icons.html +date: '2016-09-11' +author: Shai Almog +--- + +![Header Image](/blog/different-icons/kitchensink-2-flat.jpg) + +When we designed the icon for the new Kitchen Sink demo we tried to use material design principals. We thought it +would look reasonable on iOS but it looked awful. So we decided to adapt the design and create a separate +yet similar icon for iOS. + +This is actually quite common but many developers aren’t aware of how easy it is to do these sort of things. The +build process for Codename One is mostly transparent and you can replace/customize pieces of it. In this +case we edited the `build.xml` file and modified this build target: + + + + + + +We changed one line: + + + icon="iosicon.png" + +We also had to do the same change in the release target: + + + + +This is really convenient as it allows you to override and automate many stages of the build. Every device build +has a target and you can modify things such as which files get packaged. + +### XML Updates + +The pitfall with this technique is that XML files are updated occasionally. The Codename One Settings application +or the IDE preferences will detect out of date `build.xml` files and offer to update them, this might be required to +take advantage of newer features such as offline build…​ + +This update will eliminate your changes so you will need to reintegrate them. If you have many changes just move them +to an external file that you can include in the right spot so re-integrating changes is easy. Also make sure to keep +the build.xml in version control so an accidental overwrite won’t destroy your work. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — September 16, 2016 at 5:29 am ([permalink](https://www.codenameone.com/blog/different-icons.html#comment-22726)) + +> bryan says: +> +> Re Kitchen Sink – I’ve been looking at the source to see how some of the stuff in the demo is done, and it would be really good if there were more comments or description in the code (or accompanying the demo) so developers could copy some of the techniques used. There’s a bunch of stuff obviously possible with CN1, but much of it is hidden away and not always obvious that what’s possible. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdifferent-icons.html) + + +### **Shai Almog** — September 16, 2016 at 9:41 am ([permalink](https://www.codenameone.com/blog/different-icons.html#comment-23091)) + +> Shai Almog says: +> +> Here is a neat trick you can do: +> Press the edit icon on the top right and just insert your comments or even “can you explain this?” comments. Once done just click the pull request button. +> +> I will merge the pull request and then fix the “explain this” comments… You don’t even need to check out the project. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdifferent-icons.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/disable-screenshots-copy-paste.md b/docs/website/content/blog/disable-screenshots-copy-paste.md new file mode 100644 index 0000000000..654872f97f --- /dev/null +++ b/docs/website/content/blog/disable-screenshots-copy-paste.md @@ -0,0 +1,37 @@ +--- +title: Disable Screenshot, Copy & Paste +slug: disable-screenshots-copy-paste +url: /blog/disable-screenshots-copy-paste/ +original_url: https://www.codenameone.com/blog/disable-screenshots-copy-paste.html +aliases: +- /blog/disable-screenshots-copy-paste.html +date: '2017-01-31' +author: Shai Almog +--- + +![Header Image](/blog/disable-screenshots-copy-paste/security.jpg) + +Continuing our security trend from the past month we have a couple of new features for Android security that allow us to block the user from taking a screenshot or copying & pasting data from fields. Notice that these features might fail on jailbroken devices so you might want to [check for jailbreak/rooting](/blog/jailbreak-rooting-detection.html) first. + +Blocking screenshots is an Android specific feature that can’t be implemented on iOS. This is implemented by classifying the app window as secure and you can do that via the build hint `android.disableScreenshots=true`. Once that is added screenshots should no longer work for the app, this might impact other things as well such as the task view etc. + +We will add the ability to block copy & paste on Android in the coming update. We will add this feature to iOS as we move forward and it should work with the same semantics. You can block copy & paste globally or on a specific field, to block this globally use: + + + Display.getInstance().setProperty("blockCopyPaste", "true"); + +To block this on a specific field do: + + + textCmp.putClientProperty("blockCopyPaste", Boolean.TRUE); + +__ | Notice that the inverse of using `false` might not work as expected +---|--- + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/discontinuing-the-corporate-server-old-push-server.md b/docs/website/content/blog/discontinuing-the-corporate-server-old-push-server.md new file mode 100644 index 0000000000..d8fd62d1b8 --- /dev/null +++ b/docs/website/content/blog/discontinuing-the-corporate-server-old-push-server.md @@ -0,0 +1,53 @@ +--- +title: Discontinuing the Corporate Server & Old Push Servers +slug: discontinuing-the-corporate-server-old-push-server +url: /blog/discontinuing-the-corporate-server-old-push-server/ +original_url: https://www.codenameone.com/blog/discontinuing-the-corporate-server-old-push-server.html +aliases: +- /blog/discontinuing-the-corporate-server-old-push-server.html +date: '2016-06-04' +author: Shai Almog +--- + +![Header Image](/blog/discontinuing-the-corporate-server-old-push-server/push-megaphone.png) + +The corporate server offering has always been controversial and problematic both within Codename One & +for the customers who bought that service. We struggled a lot with trying to get it just right but with every installation +we ran into a painful reminder of exactly why we chose to use the cloud. After discussing this with our existing +corporate customers we came to the conclusion that we need something better that would still address the +requirement of offline building. + +We have something in the works based on the feedback from these customers and we intend to roll it out +at the 3.6 timeline (end of year, note that these are tentative plans…​). If you are currently evaluating Codename One +and are interested in the ability to build offline then please use the [contact us section](/contact-us.html) +to discuss your interest with our sales dept. + +__ | We already discussed this extensively with all existing corporate customers, this post is strictly for people evaluating Codename One +and the corporate server! +---|--- + +Since the upcoming replacement isn’t finished we can’t really discuss tentative plans but we will discuss planned +features/requirements in some cases to make sure that our upcoming plans align with corporate requirements. + +Currently the replacement for the corporate server is scheduled as a private beta on Q4 2016 so we are looking +for interested parties to try it out/provide feedback. + +### Discontinuing the Old Push Servers + +We plan to retire the old push servers currently using the appspot URL. We reviewed the list of developers still +using it and from conversations with most of them 3 months should be enough time to completely phase +out the old servers. + +Most developers have migrated to the new push servers which as of now are our only supported option. Even +most of those still using the old servers are mostly using them for legacy installs…​ + +Please try to migrate away within the next 3 months. At that time we will evaluate the traffic to these servers +and decide whether to take these servers offline. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/dont-block-the-ui.md b/docs/website/content/blog/dont-block-the-ui.md new file mode 100644 index 0000000000..8afffe2f5c --- /dev/null +++ b/docs/website/content/blog/dont-block-the-ui.md @@ -0,0 +1,156 @@ +--- +title: Don't Block The UI +slug: dont-block-the-ui +url: /blog/dont-block-the-ui/ +original_url: https://www.codenameone.com/blog/dont-block-the-ui.html +aliases: +- /blog/dont-block-the-ui.html +date: '2014-11-16' +author: Shai Almog +--- + +![Header Image](/blog/dont-block-the-ui/dont-block-the-ui-1.png) + + + + + +![Picture](/blog/dont-block-the-ui/dont-block-the-ui-1.png) + + + + + + + + + + + + +I’ve talked with many end users about their badly written apps + + + + + + + + + + + + + + + + + + + + + + + + + +grievances + + + + + +and I’ve come to the conclusion that it isn’t a matter of native vs. cross platform or even HTML. Its a frustration issue, driven by unintuitive apps (hidden gestures etc.) and slow performance. + +The slow performance bit is the most misunderstood, there is a “feeling” of sluggishness that people complain about but when users complain about performance its usually not related to that but rather something far more mundane… When users complain about performance its often over the infinite rotating wheel covering the entire UI (InfiniteProgress dialog in Codename One), which makes them stand around like idiots waiting for their phone to let them touch it again! + +This is annoying, frustrating and I can name quite a few native apps that do this for routine data! + +When we added the InfiniteProgress dialog it was intended for use only with truly blocking operations e.g. login. However, looking back I can see that we too abused this capability in our demos and this might have inspired some developers to do the same. + +One of the advantages native apps have is the ability to cache everything, we can always show locally cached data and fetch in the background. We can indicate the data is stale in some way or that we haven’t connected when working with live data but we shouldn’t block the user when possible. You can do something trivial to indicate progress e.g.: + + + + + + + + + + +* * * + + + + + + + + + +This is naturally trivial but we can go much further than this by caching data locally and writing code that works seamlessly when running online/offline. Classes such as +[ +URLImage +](http://www.codenameone.com/3/post/2014/03/image-from-url-made-easy.html) +and ImageDownloadService can become very handy since they seamlessly handle such cases. + +You can display a “stale” indicator on top of a component to show that you are in offline mode or that the component contains changes that weren’t yet synchronized to the server, a trick we sometimes do is to place an InfiniteScroll on top of a component to indicate that it is being synchronized. Its important not to overdo this since the InfiniteScroll triggers repaints that will slow the responsiveness of your application! + +E.g: + + + + + + + + + + + + + + + + + + +Even if your application is very server bound, you can show the last UI forms from the last server connection. This is crucial since often a user would check his device to see the last thing that was open and if the application was suspended since the last run he wouldn’t like to restart the process of digging deeper into the device. + +This isn’t a new concept, the Palm Pilot was remarkably successful thanks to its amazing performance despite having relatively weak hardware even compared to its contemporaries. Palm demanded that the software act like hardware, when you press a physical button you expect instant gratification and they wanted apps to act in the same way (admittedly apps at that time usually didn’t do networking). + + + + + + + + + + + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Javier Anton** — August 17, 2020 at 8:15 am ([permalink](https://www.codenameone.com/blog/dont-block-the-ui.html#comment-24329)) + +> [Javier Anton](https://lh3.googleusercontent.com/a-/AAuE7mDRjHkEvAZNXquh9p7Oo00ey1yOwNzZ0SrFwD0IVA) says: +> +> I will add here my 2 cents… blocking the UI of a BrowserComponent will result in the underlying JS being stopped by Safari. So it is very bad to block a Form containing a BrowserComponent on iOS +> It has taken me a long time to realise this… and from my own tests I can see that Apple has restricted the bg JS even more recently +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdont-block-the-ui.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/dont-touch-that-code.md b/docs/website/content/blog/dont-touch-that-code.md new file mode 100644 index 0000000000..a0f445aed8 --- /dev/null +++ b/docs/website/content/blog/dont-touch-that-code.md @@ -0,0 +1,44 @@ +--- +title: Don't Touch That Code +slug: dont-touch-that-code +url: /blog/dont-touch-that-code/ +original_url: https://www.codenameone.com/blog/dont-touch-that-code.html +aliases: +- /blog/dont-touch-that-code.html +date: '2017-10-17' +author: Shai Almog +--- + +![Header Image](/blog/dont-touch-that-code/generic-java-2.jpg) + +Last week scrolling broke and we had a few relatively complex regressions. This can be traced back to a change we did to the `getComponentAt(x, y)` method, this change in itself fixed a problematic bug but triggered far worse bugs and we just had to revert the whole thing…​ + +So why did we even do a change to a method that’s so deep in the code and so risky? + +The logic behind that is to prevent situations like this. `getComponentAt(x, y)` is a remarkably important method which is used all over the place to implement touch interface logic. Unfortunately, as one of those methods that evolved it became “unwieldy” and because it’s so deep we tried to avoid changing it…​ + +> Don’t touch it! It works! + +— Hacker Culture + +These types of methods exist in every project and they form code rot around them. That’s why we try to avoid that mentality and try to improve on the things that are working. Sometimes in cases such as this, we fail. But more often than not we succeed and that is truly important. + +### Why this Method? + +As I mentioned before `getComponentAt(x, y)` is used internally all over the place. The benefit of code reuse goes well beyond basic aesthetics and code reduction. It guarantees better test coverage, increased stability and performance as the compiler & optimizations can do much more. + +However, that also means a method can become a point of hacks that impact everyone. So now that we reverted the change we’ll need to go over every use case and surgically remove the usage of this method so we can understand why these regressions happened and hopefully make the code more sensible. + +Unfortunately, this delays our planned migration to the on-top side menu which we were hoping to do this week. Right now the menu just doesn’t work properly with peer components which was the exact fix we aimed at here. + +### What does that Mean? + +It means we might not be able to finish everything we wanted for the 3.8 release and need to move even more things to 3.9. Accessibility is something I specifically wanted to deliver for 3.8 but it’s a non-trivial feature so it probably won’t make it with our existing commitments. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/downloads-callbacks-signature-more.md b/docs/website/content/blog/downloads-callbacks-signature-more.md new file mode 100644 index 0000000000..063557af4f --- /dev/null +++ b/docs/website/content/blog/downloads-callbacks-signature-more.md @@ -0,0 +1,239 @@ +--- +title: Downloads, Callbacks, Signature & More +slug: downloads-callbacks-signature-more +url: /blog/downloads-callbacks-signature-more/ +original_url: https://www.codenameone.com/blog/downloads-callbacks-signature-more.html +aliases: +- /blog/downloads-callbacks-signature-more.html +date: '2016-02-28' +author: Shai Almog +--- + +![Header Image](/blog/downloads-callbacks-signature-more/signature.jpg) + +We’ve had a busy week working with several customers on various tasks/issues as well as the documentation +which is practically unrecognizable by now (more than 600 pages by now). As a result a lot of small fixes and +enhancements were made to the code as well as one new niche component. + +### ConnectionRequest.downloadImageToStorage + +We have multiple ways to download an image and our general favorite is the [URLImage](https://www.codenameone.com/javadoc/com/codename1/ui/URLImage.html). +However, the [URLImage](https://www.codenameone.com/javadoc/com/codename1/ui/URLImage.html) assumes +that you know the size of the image in advance or that you are willing to resize it. In that regard it works great for +some use cases but not so much for others. + +In those other cases we usually recommend [one of the Util methods](https://www.codenameone.com/javadoc/com/codename1/io/Util.html#downloadUrlToStorageInBackground-java.lang.String-java.lang.String-com.codename1.ui.events.ActionListener-). +However, that might not always be appropriate since some edge cases might require more complex +manipulation of requests e.g. making a `POST` request to get an image. + +__ | Adding global headers is another use case but you can use +[addDefaultHeader](https://www.codenameone.com/javadoc/com/codename1/io/NetworkManager.html#addDefaultHeader-java.lang.String-java.lang.String-) +to add those. +---|--- + +To make this process simpler we added a set of helper methods to +[ConnectionRequest that downloads images directly](https://www.codenameone.com/javadoc/com/codename1/io/ConnectionRequest.html#downloadImageToStorage-java.lang.String-com.codename1.util.SuccessCallback-). + +These methods complement the `Util` methods but go a bit further and feature very terse syntax e.g. we can just +download a `ConnectionRequest` to `Storage` using code like this: + + + request.downloadImageToStorage(url, (img) -> theImageIsHereDoSomethingWithIt(img)); + +### New Callback & Callback Dispatcher + +You will notice that the terse code above accepted an argument that isn’t an `ActionListener` or a `Runnable` +since it passes an `Image` object in the callback. + +Historically we had a little known interface in Codename One that was inspired by GWT called +[Callback](https://www.codenameone.com/javadoc/com/codename1/util/Callback.html). This interface +was used mainly for webservice calls so it had `onSuccess`/`onError` methods and a generic based response. + +With Java 8 lambdas it occurred to us that it makes more sense to split this interface into two interfaces so +we can write more terse code and so we now have: +[SuccessCallback](https://www.codenameone.com/javadoc/com/codename1/util/SuccessCallback.html) & +[FailureCallback](https://www.codenameone.com/javadoc/com/codename1/util/FailureCallback.html). + +These are pretty convenient and I’m pretty sure we’ll use them elsewhere. + +### Signature + +As part of his work for a customer Steve implemented the [SignatureComponent](https://www.codenameone.com/javadoc/com/codename1/components/SignatureComponent.html). +This allows an app to show a surface where the user can scribble a signature to approve a contract or detail +within the app. + +![The Signature Component](/blog/downloads-callbacks-signature-more/components-signature2.png) + +Simple usage of the `SignatureComponent` class looks like this: + + + Form hi = new Form("Signature Component"); + hi.setLayout(new BoxLayout(BoxLayout.Y_AXIS)); + hi.add("Enter Your Name:"); + hi.add(new TextField()); + hi.add("Signature:"); + SignatureComponent sig = new SignatureComponent(); + sig.addActionListener((evt)-> { + System.out.println("The signature was changed"); + Image img = sig.getSignatureImage(); + // Now we can do whatever we want with the image of this signature. + }); + hi.addComponent(sig); + hi.show(); + +### Small Changes + +#### Component.remove() + +We added the ability to do [Component.remove()](https://www.codenameone.com/javadoc/com/codename1/ui/Component.html#remove--). +This is really shorthand syntax for the somewhat contrived `getParent()` syntax but it’s also pretty helpful when +we aren’t sure if there is a parent. + +So in effect it saves us the cost of an additional if statement. + +#### Generic Action Listener & NetworkEvent Callbacks + +Up until now [NetworkEvent](https://www.codenameone.com/javadoc/com/codename1/io/NetworkEvent.html) +was pretty painful to use. E.g. if you wanted to monitor networking code via a listener you always had to +downcast to the `NetworkEvent` e.g.: + + + NetworkManager.getInstance().addErrorListener(new ActionListener() { + public void actionPerformed(ActionEvent ev) { + NetworkEvent e = (NetworkEvent)ev; + // do something... + } + }); + +Or with Java 8 syntax: + + + NetworkManager.getInstance().addErrorListener((ev) -> { + NetworkEvent e = (NetworkEvent)ev; + // do something... + }); + +This sucks and made us constantly rethink our decision to use `ActionListener` everywhere…​ + +Until we suddenly realized we can generify `ActionListener` which is now `ActionListener`. As a result +we made all the listener events in `NetworkManager` and `ConnectionRequest` use `NetworkEvent` +as the generic and the result is that this works: + + + NetworkManager.getInstance().addErrorListener((networkEventInstance) -> { + // do something... + }); + +#### Shorter Padding/Margin Syntax + +I’ve been writing a lot of demos and one of the things I try to do when writing demo code is to keep it as self +contained as possible so it will work on your machines. + +This is sometimes challenging as providing things such as theme instructions to reproduce my results is probably +not intuitive. So to reproduce some behaviors I use `Style` manipulation code rather than themes which are superior +but harder to convey in a manual. + +As part of that I was manipulating margin and wanted to make sure the margin is in DIPs (millimeters). The common +code for this is: + + + cmp.getAllStyles().setMarginUnit(Style.UNIT_TYPE_DIPS, Style.UNIT_TYPE_DIPS, Style.UNIT_TYPE_DIPS, Style.UNIT_TYPE_DIPS); + +This applies to all 4 sides of the margin/padding but if this seems redundant to you then you are not the only one…​ + +So from now on if you have less than 4 elements only the first one will count so this statement will be equivalent: + + + cmp.getAllStyles().setMarginUnit(Style.UNIT_TYPE_DIPS); + +This also applies to padding so you can use that syntax there. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Yaakov Gesher** — March 1, 2016 at 10:15 am ([permalink](https://www.codenameone.com/blog/downloads-callbacks-signature-more.html#comment-22509)) + +> Great stuff! It’s wonderful to see constant API improvements and new features every month! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdownloads-callbacks-signature-more.html) + + +### **Flying Bytes Jansen** — March 9, 2016 at 2:46 pm ([permalink](https://www.codenameone.com/blog/downloads-callbacks-signature-more.html#comment-22477)) + +> Flying Bytes Jansen says: +> +> The SignatureComponent is just what I need. When will it be available? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdownloads-callbacks-signature-more.html) + + +### **Shai Almog** — March 10, 2016 at 3:44 am ([permalink](https://www.codenameone.com/blog/downloads-callbacks-signature-more.html#comment-22649)) + +> Shai Almog says: +> +> It was released yesterday. Just do an Update Client Libs to get the latest and it will “just work”. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdownloads-callbacks-signature-more.html) + + +### **Flying Bytes Jansen** — March 10, 2016 at 8:49 am ([permalink](https://www.codenameone.com/blog/downloads-callbacks-signature-more.html#comment-22541)) + +> Flying Bytes Jansen says: +> +> Great, thank you! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdownloads-callbacks-signature-more.html) + + +### **Mahmoud** — July 30, 2018 at 9:56 am ([permalink](https://www.codenameone.com/blog/downloads-callbacks-signature-more.html#comment-23766)) + +> Mahmoud says: +> +> Dear Shai, +> +> There is an issue in Signature Component (ios,android) i cant draw dot(point) by one click +> to draw it i need to press down and small move to any side +> your help plz +> +> BR, +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdownloads-callbacks-signature-more.html) + + +### **Shai Almog** — July 31, 2018 at 5:20 am ([permalink](https://www.codenameone.com/blog/downloads-callbacks-signature-more.html#comment-23768)) + +> Shai Almog says: +> +> Hi, +> I’ve made a small change which should hopefully resolve this. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdownloads-callbacks-signature-more.html) + + +### **Mahmoud** — July 31, 2018 at 5:38 am ([permalink](https://www.codenameone.com/blog/downloads-callbacks-signature-more.html#comment-23799)) + +> Mahmoud says: +> +> you mean new change in new bulid or new update lib? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdownloads-callbacks-signature-more.html) + + +### **Shai Almog** — August 2, 2018 at 5:51 am ([permalink](https://www.codenameone.com/blog/downloads-callbacks-signature-more.html#comment-23441)) + +> Shai Almog says: +> +> In the library. We’ll have the fix after you update this Friday. If it happens after that let me know. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdownloads-callbacks-signature-more.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/dr-sbaitso-coming-to-riga.md b/docs/website/content/blog/dr-sbaitso-coming-to-riga.md new file mode 100644 index 0000000000..2b4289e6c2 --- /dev/null +++ b/docs/website/content/blog/dr-sbaitso-coming-to-riga.md @@ -0,0 +1,58 @@ +--- +title: Dr. Sbaitso Coming To Riga +slug: dr-sbaitso-coming-to-riga +url: /blog/dr-sbaitso-coming-to-riga/ +original_url: https://www.codenameone.com/blog/dr-sbaitso-coming-to-riga.html +aliases: +- /blog/dr-sbaitso-coming-to-riga.html +date: '2015-01-13' +author: Shai Almog +--- + +![Header Image](/blog/dr-sbaitso-coming-to-riga/dr-sbaitso-coming-to-riga-1.png) + + + + + +![Picture](/blog/dr-sbaitso-coming-to-riga/dr-sbaitso-coming-to-riga-1.png) + + + + + + + + +I’ll be speaking at +[ +Riga Dev Day +](http://www.rigadevday.lv) +next week and I’ve been working on a demo for the conference. Back in my teen years I bought the SoundBlaster 1.0 which was one of the first affordable soundcards for the PC. One of the killer demos that shipped with it was a silly command line AI psychoanalyst by the name of +[ +Dr. Sbaitso +](http://en.wikipedia.org/wiki/Dr._Sbaitso) +that would try to dish out advice in all caps… + +It was actually surprisingly cool and gave a wide set of answers that were often pretty clever. As a salute to the wonderful developer who built that we created a simple chat demo that is more like the iMessage UI than like Dr. Sbaitso but it does use its signature opening tagline. + +The demo uses the new Toolbar API and some other cool capabilities such as camera capture, bubble chat, instant search etc. We even added a native interface so it will speak just like the original doctor! + +We hope to make some videos that cover the new demo and how it works. + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/dr-sbaitso-revisited.md b/docs/website/content/blog/dr-sbaitso-revisited.md new file mode 100644 index 0000000000..26da448a49 --- /dev/null +++ b/docs/website/content/blog/dr-sbaitso-revisited.md @@ -0,0 +1,114 @@ +--- +title: Dr. Sbaitso Revisited +slug: dr-sbaitso-revisited +url: /blog/dr-sbaitso-revisited/ +original_url: https://www.codenameone.com/blog/dr-sbaitso-revisited.html +aliases: +- /blog/dr-sbaitso-revisited.html +date: '2016-06-06' +author: Shai Almog +--- + +![Header Image](/blog/dr-sbaitso-revisited/drsbaitso.jpg) + +Dr. Sbaitso is one of our newer demos. We wrote it for a workshop at JavaZone a couple of years ago and it +proved to be an excellent tutorial on many complex abilities of Codename One. It captures images from the +camera, rounds them, does dynamic search with a chat like bubble interface…​ + +**Check the live version running on the right hand side thanks to the power of the Codename One JavaScript port!** + +But the coolest part is the speech synthesis…​ + +It uses native interfaces to access the text-to-speech capabilities of the device and “says” what the “doctor” is +saying. This both demonstrates native access and the rather cool TTS functionality. + +### What’s to Improve? + +The demo is already so good and relatively terse, there isn’t much to improve about it. + +We naturally updated it to Java 8 and the newer terse syntax which cleaned up a bit of the UI. We also replaced +the next command with an arrow material design icon which is more attractive…​ + +But the coolest change is that we added native interface support for JavaScript so Dr. Sbaitso now speaks in +the Chrome browser! + +This works really well and runs very smoothly on my desktop, it’s not ideal because speech synthesis isn’t +widely supported by browsers and I wasn’t able to get it to work on firefox or any other browser. But it’s still +remarkably cool. + +__ | This pretty much shows off the benefit of having a native framework vs. the pain of web fragmentation…​ +---|--- +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Ross Taylor** — June 16, 2016 at 7:44 pm ([permalink](https://www.codenameone.com/blog/dr-sbaitso-revisited.html#comment-21630)) + +> Ross Taylor says: +> +> Hi Shai, would it be possible to create text input that allows for paragraph to be created and emojis to be inserted? Also allow to create a bubble to format text appropriately when needed like bullet points (if pasted from a document that does have them), telephone numbers (tapping on numbers to trigger events like calling or saving to address book) , URL links (underline them and when tapped to open web browser), i.a.w, pretty much like the way bubbles displays the text richly like existing IMs you get now? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdr-sbaitso-revisited.html) + + +### **Shai Almog** — June 17, 2016 at 3:44 am ([permalink](https://www.codenameone.com/blog/dr-sbaitso-revisited.html#comment-22697)) + +> Shai Almog says: +> +> Hi, +> You can insert emojiis on the device today and it should work fine for this and other apps. +> However, what you are talking about is called a “rich edit component” we have a cn1lib that supports that somewhere (Steve did it) thru a web browser UI. The problem is that Android and iOS have rather bad support for that concept and it’s rather different between the OS’s. +> It’s something we wanted to integrate a while back but we didn’t have any actionable user demand which is really needed for such a problematic task. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdr-sbaitso-revisited.html) + + +### **ssybesma** — December 30, 2016 at 3:43 am ([permalink](https://www.codenameone.com/blog/dr-sbaitso-revisited.html#comment-23137)) + +> ssybesma says: +> +> You have to be kidding…all it does is ask you questions about what you just said. Dr. Sbaitso actually is intelligent compared to this. He does more than just that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdr-sbaitso-revisited.html) + + +### **Shai Almog** — December 30, 2016 at 5:20 am ([permalink](https://www.codenameone.com/blog/dr-sbaitso-revisited.html#comment-23256)) + +> Shai Almog says: +> +> 🙂 +> +> That’s the nature of demos. I totally meant to write a decent AI chat and instead focused on the other features. By the time I was done I couldn’t justify writing more code for something that’s meant to teach UI programming and native interfaces… +> +> Feel free to submit a pull request though, all the logic is in [AI.java]() so it should be pretty easy. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdr-sbaitso-revisited.html) + + +### **ssybesma** — December 30, 2016 at 6:03 am ([permalink](https://www.codenameone.com/blog/dr-sbaitso-revisited.html#comment-23301)) + +> ssybesma says: +> +> I appreciate that you were not offended and I apologize for being a bit harsh. I do look forward to the eventual release of an application that does Dr. Sbaitso one better. The voice has to be the same, though…sorry. I’m sentimental. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdr-sbaitso-revisited.html) + + +### **Shai Almog** — December 31, 2016 at 12:16 pm ([permalink](https://www.codenameone.com/blog/dr-sbaitso-revisited.html#comment-23075)) + +> Shai Almog says: +> +> If I’d spend time on this I’d work on the AI but I doubt I’ll get any time to work on that. When I initially presented the demo no one knew about the original so the points were a bit lost on them… Plus it made me feel old 😉 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdr-sbaitso-revisited.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/dr-sbaitso.md b/docs/website/content/blog/dr-sbaitso.md new file mode 100644 index 0000000000..217f7e5f73 --- /dev/null +++ b/docs/website/content/blog/dr-sbaitso.md @@ -0,0 +1,80 @@ +--- +title: Dr. Sbaitso +slug: dr-sbaitso +url: /blog/dr-sbaitso/ +original_url: https://www.codenameone.com/blog/dr-sbaitso.html +aliases: +- /blog/dr-sbaitso.html +date: '2015-02-01' +author: Shai Almog +--- + +![Header Image](/blog/dr-sbaitso/dr-sbaitso-1.png) + + + + + +![Picture](/blog/dr-sbaitso/dr-sbaitso-1.png) + + + + + + +I recently flew to +[ +dev day at Riga +](http://rigadevday.lv/) +, I was quite ill before the trip so it was pretty difficult and that’s the main reason I didn’t make a trip report like I normally do. However, the conference and the people running it did seem like a whole lot of fun that unfortunately I was in no shape to enjoy. + +I did prepare a demo/presentation for the trip though and since I gave my talk under the influence of medication I think its wise to post a tutorial to the demo I did here both for those who were in attendance and for the rest of the Codename One community. + +The demo I made is a homage to an old Soundblaster demo, its generally a chat app between you and an AI that I designed to look like iMessage. It uses text to speech (with native interfaces) to vocalize the responses of the “AI”. Notice the AI is really trivial and I don’t cover it in the video tutorials below. + +You can see the full source code of the demo in our +[ +demos directory here +](https://code.google.com/p/codenameone/source/browse/trunk/Demos/) +. Here are videos explaining pretty much the whole demo. + + + + +* * * + + + + + + + + + + + + + + + + + + + + + + + + + + + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/drag-and-drop-uploader.md b/docs/website/content/blog/drag-and-drop-uploader.md new file mode 100644 index 0000000000..5f7c5697f4 --- /dev/null +++ b/docs/website/content/blog/drag-and-drop-uploader.md @@ -0,0 +1,57 @@ +--- +title: Drag and Drop Uploader +slug: drag-and-drop-uploader +url: /blog/drag-and-drop-uploader/ +original_url: https://www.codenameone.com/blog/drag-and-drop-uploader.html +aliases: +- /blog/drag-and-drop-uploader.html +date: '2016-08-07' +author: Shai Almog +--- + +![Header Image](/blog/drag-and-drop-uploader/generic-java-1.jpg) + +One of our enterprise customers needed help with file upload from the desktop. E.g. in his Codename One app running in the browser or desktop he wanted the ability to drag a file. Somewhat like we can drag a file into gmails compose window. + +This doesn’t make sense within Codename One as something like that doesn’t exist on mobile devices or even tablets. Creating a [cn1lib that implements this functionality](https://github.com/shannah/cn1-native-data-transfer) does make sense, so [Steve did just that](https://github.com/shannah/cn1-native-data-transfer). + +You can get started by installing the library using our [extension manager tool](http://www.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html). + +Check out the live demo here on the right side, drag an image into the phone simulator to add it to the form. + +__ | I chose to use a phone skin out of habit but this obviously isn’t useful for actual devices…​ +---|--- + +This is the code that makes it all happen: + + + Form hi = new Form("Drag and Drop Demo"); + + if (DropTarget.isSupported()) { + DropTarget dnd = DropTarget.create((evt)->{ + String srcFile = (String)evt.getSource(); + System.out.println("Src file is "+srcFile); + System.out.println("Location: "+evt.getX()+", "+evt.getY()); + if (srcFile != null) { + try { + Image img = Image.createImage(FileSystemStorage.getInstance().openInputStream(srcFile)); + hi.add(img); + hi.revalidate(); + } catch (IOException ex) { + Log.e(ex); + } + } + }, Display.GALLERY_IMAGE); + } + hi.setLayout(new BoxLayout(BoxLayout.Y_AXIS)); + hi.setScrollableY(true); + hi.addComponent(new SpanLabel("Drag photos from your desktop into this app")); + hi.show(); + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/drop-it-introducing-dropbox-integration.md b/docs/website/content/blog/drop-it-introducing-dropbox-integration.md new file mode 100644 index 0000000000..2af834ad98 --- /dev/null +++ b/docs/website/content/blog/drop-it-introducing-dropbox-integration.md @@ -0,0 +1,163 @@ +--- +title: Drop It – Introducing Dropbox Integration +slug: drop-it-introducing-dropbox-integration +url: /blog/drop-it-introducing-dropbox-integration/ +original_url: https://www.codenameone.com/blog/drop-it-introducing-dropbox-integration.html +aliases: +- /blog/drop-it-introducing-dropbox-integration.html +date: '2013-05-12' +author: Shai Almog +--- + +![Header Image](/blog/drop-it-introducing-dropbox-integration/drop-it-introducing-dropbox-integration-1.png) + + + + +[ +![Dropbox](/blog/drop-it-introducing-dropbox-integration/drop-it-introducing-dropbox-integration-1.png) +](https://code.google.com/p/dropbox-codenameone-sdk/) + + + +We are working on something exciting, more on that next week (hopefully). One of the things we needed was a way to access files on a device, e.g. images, etc. however this is a painful and fragmented subject. + + +Most of my files are still on my laptop and not on my tablet or phone and moving them back and forth isn’t + +convenient… Luckily we have +[ +Dropbox +](https://code.google.com/p/dropbox-codenameone-sdk/) +, this neat tool has really helped us collaborate as a startup and has made many painful things remarkably easy. + + +So Chen came up with an amazing plugin that allows us to treat drop box as yet another file system we can use to extract files from! + + +(He made use of some excellent work contributed to the community by +[ +Eric Coolman +](http://gadgets.coolman.ca/) +for Oauth 1.x support!). + + + + + +This is absolutely spectacular and hugely convenient! + + +You can download his source code + +[ +here +](https://code.google.com/p/dropbox-codenameone-sdk/) + +its a Codename One Library project so you just compile it in NetBeans then add it to the lib directory of either Eclipse or NetBeans. Then right click the project + +and press refresh libs and it should “just work”. + +This is a brand new project and Chen would love some contributions and collaborations there so feel free to contribute. + + +So how do you use it? + + +First you need to create a Dropbox core application +[ +here +](https://www.dropbox.com/developers/apps) +, this will give you the two keys you need below. Keep in mind that in order to use it for more than one account you will need to select an option during the process and in order to use it in production you will need specific approval. + + +** +Notice: +** +for this code to work properly you will need a “proper” browser component, so you will need Java 7 to be configured properly with FX so the browser component will work as expected on the simulator. + + + + + + +First you just need to login: + + +* * * + + + + +The code above logs in to Dropbox then invokes the Dropbox file picker code which I’ll show you below using our tree component. + + +The code below completes the picture by creating a file picker tree allowing + +us to download a file from dropbox and do whatever we please with it! + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — May 16, 2013 at 9:20 pm ([permalink](https://www.codenameone.com/blog/drop-it-introducing-dropbox-integration.html#comment-21751)) + +> Anonymous says: +> +> This is all great. Also I want to know when are you going to support the new Asha software platform? Or are you going to support it at all? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdrop-it-introducing-dropbox-integration.html) + + +### **Anonymous** — May 17, 2013 at 6:19 pm ([permalink](https://www.codenameone.com/blog/drop-it-introducing-dropbox-integration.html#comment-21737)) + +> Anonymous says: +> +> J2ME platform is supported, what feature are you missing? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdrop-it-introducing-dropbox-integration.html) + + +### **Anonymous** — October 31, 2013 at 11:43 am ([permalink](https://www.codenameone.com/blog/drop-it-introducing-dropbox-integration.html#comment-21771)) + +> Anonymous says: +> +> Dear Chen, +> +> I would like to discuss with you in detail features of your plugin and its possible use in the application we are developing. Please contact me ASAP. +> +> Best regards, +> +> Ibrokhim +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdrop-it-introducing-dropbox-integration.html) + + +### **Anonymous** — January 24, 2014 at 11:44 am ([permalink](https://www.codenameone.com/blog/drop-it-introducing-dropbox-integration.html#comment-21642)) + +> Anonymous says: +> +> Is it possible to upload a file as well? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdrop-it-introducing-dropbox-integration.html) + + +### **Anonymous** — January 24, 2014 at 3:40 pm ([permalink](https://www.codenameone.com/blog/drop-it-introducing-dropbox-integration.html#comment-22037)) + +> Anonymous says: +> +> Not at the moment although it should be doable in theory. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdrop-it-introducing-dropbox-integration.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/dynamic-autocomplete.md b/docs/website/content/blog/dynamic-autocomplete.md new file mode 100644 index 0000000000..0cf025d15b --- /dev/null +++ b/docs/website/content/blog/dynamic-autocomplete.md @@ -0,0 +1,220 @@ +--- +title: Dynamic AutoComplete +slug: dynamic-autocomplete +url: /blog/dynamic-autocomplete/ +original_url: https://www.codenameone.com/blog/dynamic-autocomplete.html +aliases: +- /blog/dynamic-autocomplete.html +date: '2016-07-13' +author: Shai Almog +--- + +![Header Image](/blog/dynamic-autocomplete/dynamic-autocomplete.png) + +With the fix for [issue #1694](https://github.com/codenameone/CodenameOne/issues/1694) we can now have +a moderately simple method of creating an +[AutoCompleteTextField](https://www.codenameone.com/javadoc/com/codename1/ui/AutoCompleteTextField.html) +that works with a webservice. This has been requested quite often and was quite frustrating to implement in the past +it is now relatively simple with just a few lines of code. + +**Check out the live demo using the JavaScript port on the right side here** + +You can see the full working sample of this project in this +[github repository](https://github.com/codenameone/AutoCompleteWebservice) notice that you will need to fill +in a google web API key for the webservice to work as explained +[here](https://developers.google.com/places/web-service/get-api-key). + +The sample works relatively simply, instead of passing a fixed list of elements we pass a model to the auto +complete and then just modify the model. The auto complete updates itself based on the modification to the +model which is completely asynchronous. + +The main thing we need to do is override the `filter` method and mutate the model there. + +Check out the main code of this app below: + + + Form hi = new Form("AutoComplete", new BoxLayout(BoxLayout.Y_AXIS)); + if(apiKey == null) { + hi.add(new SpanLabel("This demo requires a valid google API key to be set in the constant apiKey, " + + "you can get this key for the webservice (not the native key) by following the instructions here: " + + "https://developers.google.com/places/web-service/get-api-key")); + hi.getToolbar().addCommandToRightBar("Get Key", null, e -> Display.getInstance().execute("https://developers.google.com/places/web-service/get-api-key")); + hi.show(); + return; + } + final DefaultListModel options = new DefaultListModel<>(); + AutoCompleteTextField ac = new AutoCompleteTextField(options) { + @Override + protected boolean filter(String text) { + if(text.length() == 0) { + return false; + } + String[] l = searchLocations(text); + if(l == null || l.length == 0) { + return false; + } + + options.removeAll(); + for(String s : l) { + options.addItem(s); + } + return true; + } + }; + ac.setMinimumElementsShownInPopup(5); + hi.add(ac); + hi.show(); + +Notice that it relies on a call to the Google webservice as such: + + + String[] searchLocations(String text) { + try { + if(text.length() > 0) { + ConnectionRequest r = new ConnectionRequest(); + r.setPost(false); + r.setUrl("https://maps.googleapis.com/maps/api/place/autocomplete/json"); + r.addArgument("key", apiKey); + r.addArgument("input", text); + NetworkManager.getInstance().addToQueueAndWait(r); + Map result = new JSONParser().parseJSON(new InputStreamReader(new ByteArrayInputStream(r.getResponseData()), "UTF-8")); + String[] res = Result.fromContent(result).getAsStringArray("//description"); + return res; + } + } catch(Exception err) { + Log.e(err); + } + return null; + } +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Carlos** — July 14, 2016 at 3:46 pm ([permalink](https://www.codenameone.com/blog/dynamic-autocomplete.html#comment-22871)) + +> Carlos says: +> +> Awesome, thank you, but I would take +> +> options.removeAll(); +> +> right before: +> +> if (text.length() == 0) +> +> So if the user erase to empty the textfield, the combo with the completions disappears. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdynamic-autocomplete.html) + + +### **Shai Almog** — July 15, 2016 at 4:01 am ([permalink](https://www.codenameone.com/blog/dynamic-autocomplete.html#comment-22878)) + +> Shai Almog says: +> +> Makes sense, thanks! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdynamic-autocomplete.html) + + +### **Diamond** — July 15, 2016 at 9:03 am ([permalink](https://www.codenameone.com/blog/dynamic-autocomplete.html#comment-22852)) + +> Diamond says: +> +> Hi Shai, +> +> How do I style the AutoCompleteTextField List selected item? The default color is orange on my theme and I will like to change it to blue. I’ve tried styling “AutoCompleteList”, but it doesn’t help… the whole list got changed to blue and I want only one item to change. I also tried AutoCompleteListRenderer and AutoCompleteListRendererFocus, not helping either. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdynamic-autocomplete.html) + + +### **Shai Almog** — July 16, 2016 at 4:30 am ([permalink](https://www.codenameone.com/blog/dynamic-autocomplete.html#comment-22725)) + +> Shai Almog says: +> +> Hi Diamond, +> you can use setCompletionRenderer() to set a custom renderer. It uses the standard list renderer with ListRendererFocus and ListRenderer UIID’s. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdynamic-autocomplete.html) + + +### **Diamond** — July 19, 2016 at 8:07 pm ([permalink](https://www.codenameone.com/blog/dynamic-autocomplete.html#comment-22942)) + +> Diamond says: +> +> Hi Shai, +> +> Is it possible to change the AutoComplete popup to have an icon and text? +> +> Also, is it possible to clear the text input if user didn’t choose from the popup? This is to force only suggested values in the TextField. +> +> Lastly, Can I make the popup list break line for long text? +> +> If any of these are possible, can you please guide on how to achieve this. +> +> Thank you. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdynamic-autocomplete.html) + + +### **Shai Almog** — July 20, 2016 at 4:26 am ([permalink](https://www.codenameone.com/blog/dynamic-autocomplete.html#comment-22935)) + +> Shai Almog says: +> +> Hi Diamond, +> It’s a renderer so you can do everything a renderer can do with its standard limitations. +> So icon should be easy just use your data model when you fetch the information to render the icon and potentially more than one row. +> +> However, dynamic line breaking is problematic with renderers so that won’t work. +> +> I’d love to have a way to use components in box Y instead of list+renderer for this component and the original issue actually suggested going in that direction. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdynamic-autocomplete.html) + + +### **Diamond** — July 22, 2016 at 10:57 am ([permalink](https://www.codenameone.com/blog/dynamic-autocomplete.html#comment-22785)) + +> Diamond says: +> +> ac.getHintLabel().setUIID(“CustomHintUIID”); is throwing a nullPointer exception, is there a way to fix this? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdynamic-autocomplete.html) + + +### **Shai Almog** — July 23, 2016 at 4:44 am ([permalink](https://www.codenameone.com/blog/dynamic-autocomplete.html#comment-22779)) + +> Shai Almog says: +> +> That’s standard behavior in a text area/field as well… If you didn’t call setHint(…) first the label wasn’t created so it will be null. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdynamic-autocomplete.html) + + +### **emaalam** — April 27, 2017 at 12:56 pm ([permalink](https://www.codenameone.com/blog/dynamic-autocomplete.html#comment-23346)) + +> emaalam says: +> +> Hi Shai +> i have two problems first i want to add a map in AutoCompleteTextField exactlly in DefaultListModel and after i want to add the the listmodel in my autocompletetextField second : how can i get the text when i select an element in the AutoCompleteTextField +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdynamic-autocomplete.html) + + +### **emaalam** — April 27, 2017 at 3:33 pm ([permalink](https://www.codenameone.com/blog/dynamic-autocomplete.html#comment-23250)) + +> emaalam says: +> +> hi Shai +> please answer me here [http://stackoverflow.com/qu…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fdynamic-autocomplete.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/easy-demos-flip-more.md b/docs/website/content/blog/easy-demos-flip-more.md new file mode 100644 index 0000000000..366aad1d2b --- /dev/null +++ b/docs/website/content/blog/easy-demos-flip-more.md @@ -0,0 +1,39 @@ +--- +title: Easy Demos, Flip & More +slug: easy-demos-flip-more +url: /blog/easy-demos-flip-more/ +original_url: https://www.codenameone.com/blog/easy-demos-flip-more.html +aliases: +- /blog/easy-demos-flip-more.html +date: '2015-02-22' +author: Shai Almog +--- + +![Header Image](/blog/easy-demos-flip-more/flip.png) + +![](/blog/easy-demos-flip-more/flip.png) + +One of the pains in Codename One is the access to the demos, yes we have the downloadable demo bundle and the SVN but for a compete novice to Codename One this isn’t front and center. Chen decided to address that by embedding the latest versions of the demos both into the Eclipse and the NetBeans plugins, now when you create a new Codename One project you can also create a demo project and “just run it”. This allows you to quickly learn/debug our sample code which should help with the Codename One learning curve. + +Chen and Steve also adapted the code built by Steve as part of the new graphics pipeline for [perspective transforms](http://www.codenameone.com/blog/perspective-transform) +and introduced a cool new [flip transition](/javadoc/com/codename1/ui/animations/FlipTransition.html) that you can see in the video below, its really trivial to use just set form.setTransitionOutAnimation(new FlipTransition()); and that’s it. This is already in the current plugin and you can play with it right now! + +As part of ongoing support for customers we also introduced improved location support on Android which uses the new Google Play API’s that include hybrid location. This means location should be more accurate and return a result faster, this will only be used if you integrate the Google Play Services support (which you can now rely on if you write Android native interfaces). To do that just add the build hint android.includeGPlayServices=true and this will be used seamlessly. + +The [infinite adapter API](http://www.codenameone.com/blog/till-the-end-of-the-form) is sometimes +[less intuitive](/javadoc/com/codename1/components/InfiniteScrollAdapter.html) +to developers who just want to work with a Container that makes a request for more components, to simplify this use case we added a new +[InfiniteContainer API](/javadoc/com/codename1/ui/InfiniteContainer.html) +which is based on the infinite adapter but provides a more intuitive (albeit less flexible) API. When using the infinite container API you need to subclass it +and override the fetch components method to fetch additional entries. + +Last but not least we now have a [simple weak hash map implementation](/javadoc/com/codename1/ui/util/WeakHashMap.html) that is very similar to the one in java util but under our own package at the moment. +This is a very useful class for caching temporary objects. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/easy-thread.md b/docs/website/content/blog/easy-thread.md new file mode 100644 index 0000000000..9389ef75b7 --- /dev/null +++ b/docs/website/content/blog/easy-thread.md @@ -0,0 +1,77 @@ +--- +title: Easy Thread +slug: easy-thread +url: /blog/easy-thread/ +original_url: https://www.codenameone.com/blog/easy-thread.html +aliases: +- /blog/easy-thread.html +date: '2017-05-08' +author: Shai Almog +--- + +![Header Image](/blog/easy-thread/new-features-5.jpg) + +Working with threads is usually ranked as one of the least intuitive and painful tasks in programming. This is such an error prone task that some platforms/languages took the route of avoiding threads entirely. I needed to convert some code to work on a separate thread but I still wanted the ability to communicate and transfer data from that thread. + +This is possible in Java but non-trivial, the thing is that this is relatively easy to do in Codename One with tools such as `callSerially` I can let arbitrary code run on the EDT. Why not offer that to any random thread? + +That’s why I created `EasyThread` which takes some of the concepts of Codeame One’s threading and makes them more accessible to an arbitrary thread. This way you can move things like resource loading into a separate thread and easily synchronize the data back into the EDT as needed…​ + +Easy thread can be created like this: + + + EasyThread e = EasyThread.start("ThreadName"); + +You can just send a task to the thread using: + + + e.run(() -> doThisOnTheThread()); + +But it gets better, say you want to return a value: + + + e.run((success) -> success.onSuccess(doThisOnTheThread()), (myResult) -> onEDTGotResult(myRsult)); + +Lets break that down…​ We ran the thread with the success callback on the new thread then the callback got invoked on the EDT as a result. So this code `(success) → success.onSuccess(doThisOnTheThread())` ran off the EDT in the thread and when we invoked the `onSuccess` callback it sent it asynchronously to the EDT here: `(myResult) → onEDTGotResult(myRsult)`. + +These asynchronous calls make things a bit painful to wade thru so instead I chose to wrap them in a simplified synchronous version: + + + EasyThread e = EasyThread.start("Hi"); + int result = e.run(() -> { + System.out.println("This is a thread"); + return 3; + }); + +There are a few other variants like `runAndWait` and there is a `kill()` method which stops a thread and releases its resources. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chad Elofson** — May 10, 2017 at 5:14 am ([permalink](https://www.codenameone.com/blog/easy-thread.html#comment-23513)) + +> Chad Elofson says: +> +> That’s pretty slick! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Feasy-thread.html) + + +### **Javier Anton** — February 18, 2020 at 3:51 pm ([permalink](https://www.codenameone.com/blog/easy-thread.html#comment-21384)) + +> [Javier Anton](https://lh3.googleusercontent.com/a-/AAuE7mDRjHkEvAZNXquh9p7Oo00ey1yOwNzZ0SrFwD0IVA) says: +> +> Really good, but perhaps in the future a method similar to interrupt() could be added to cancel all the pending tasks (since kill() doesn’t cancel pending tasks) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Feasy-thread.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/edit-styles-simulator.md b/docs/website/content/blog/edit-styles-simulator.md new file mode 100644 index 0000000000..5d9b0b1b0d --- /dev/null +++ b/docs/website/content/blog/edit-styles-simulator.md @@ -0,0 +1,76 @@ +--- +title: Edit Styles in Simulator +slug: edit-styles-simulator +url: /blog/edit-styles-simulator/ +original_url: https://www.codenameone.com/blog/edit-styles-simulator.html +aliases: +- /blog/edit-styles-simulator.html +date: '2017-04-11' +author: Shai Almog +--- + +![Header Image](/blog/edit-styles-simulator/uidesign.jpg) + +One of the biggest pain points in Codename One is theming, there are several things we did to alleviate the problem but it’s an inherently complex problem. One difficulty people have is in the disconnect between what we see in the UI and the styling in the designer. This creates a disconnect that is often hard to bridge. + +In the past we added the Component Inspector tool to the simulator that allows you to discover the UIID’s of the various components and change the UIID’s to see the effect. This is very helpful for inspecting a running application and understanding what we see on the screen. Unfortunately, this is a half measure as we need to see something in the Component Inspector then open it in the designer restart the app rinse/repeat…​ + +That is until now! + +With the update this week we added this: + +If you don’t have the patience for the video or don’t understand what you just saw this tool allows you to edit any style within a running app (that you built) and instantly preview the changes! + +It works with multiple res files/themes but might be “flaky” in such cases as it needs to re-apply the theme. You can open the Component Inspector by clicking Simulator → Component Inspector. You might want to use refresh when reviewing the UI. + +__ | This changes the `.res` file so if you have it open in a designer you might overwrite changes made by this tool! +---|--- + +### How does it Work? + +A while back Chen wanted to add the ability to edit a style into the new GUI builder so he created a [command line argument to the designer](/blog/using-designer-command-line-options.html). He did that after I wrote that article so it isn’t documented there but you can effectively open the style editor for of the designer using something like: + + + java -jar ~/.codenameone/designer_1.jar -style path-to-res-file.res UIID NameOfTheme + +So to edit the `Button` in `theme.res` in `MyProject` I would probably do: + + + java -jar ~/.codenameone/designer_1.jar -style ~/MyProject/src/theme.res Button Theme + +Notice that unlike the dialog that opens in the designer tool this one allows you to select the style type you wish to edit using radio buttons on the bottom. + +The edit function launches that command but it also has another function of refreshing the UI. So when editing completes we update the theme in RAM and refresh the current Form. This works well for some cases but might cause some odd conflicts. E.g. if you navigate back to a form created before it might still have the old theme. + +There might also be issues with layered themes, e.g. if you have 2 themes layered one on top of the other this might trigger a conflict. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Jérémy MARQUER** — April 12, 2017 at 2:02 pm ([permalink](https://www.codenameone.com/blog/edit-styles-simulator.html#comment-23122)) + +> Jérémy MARQUER says: +> +> Great enhancement ! 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fedit-styles-simulator.html) + + +### **Avelblood** — April 15, 2017 at 12:13 pm ([permalink](https://www.codenameone.com/blog/edit-styles-simulator.html#comment-21576)) + +> Avelblood says: +> +> Awesome. The dream comes true =) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fedit-styles-simulator.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/edit-udid-in-component-inspector.md b/docs/website/content/blog/edit-udid-in-component-inspector.md new file mode 100644 index 0000000000..764d44b853 --- /dev/null +++ b/docs/website/content/blog/edit-udid-in-component-inspector.md @@ -0,0 +1,36 @@ +--- +title: Edit UDID in Component Inspector +slug: edit-udid-in-component-inspector +url: /blog/edit-udid-in-component-inspector/ +original_url: https://www.codenameone.com/blog/edit-udid-in-component-inspector.html +aliases: +- /blog/edit-udid-in-component-inspector.html +date: '2016-04-17' +author: Shai Almog +--- + +![Header Image](/blog/edit-udid-in-component-inspector/edit-udid.png) + +One of the hard things to debug in Codename One is UIID/Padding/Margin placement which is often tricky to +get “just right”. I use the [Component Inspector](https://www.codenameone.com/manual/index.html) quite a lot to +review a layout that misbehaves and gain further insight into what’s happening in runtime. + +__ | You can gain insight into the Codename One component hierarchy by running the simulator and selecting the +Simulate → Component Inspector menu option. This will present the component hierarchy as a navigatable tree +---|--- + +Up until now the Component Inspector was a “read only” tool, with the coming update it will gain the ability to edit +the UIID field! + +This would make some things remarkably trivial as you could find if that pesky extra space is coming from the theme +by just changing the UIID to `Container`. It also helps identify components more easily within the inspector and +see under the hood of Codename One (e.g. in the [Toolbar](https://www.codenameone.com/javadoc/com/codename1/ui/Toolbar.html) +area). + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/ending-support-for-legacy-cloud.md b/docs/website/content/blog/ending-support-for-legacy-cloud.md new file mode 100644 index 0000000000..0114b31dfe --- /dev/null +++ b/docs/website/content/blog/ending-support-for-legacy-cloud.md @@ -0,0 +1,58 @@ +--- +title: Ending Support for Legacy Cloud +slug: ending-support-for-legacy-cloud +url: /blog/ending-support-for-legacy-cloud/ +original_url: https://www.codenameone.com/blog/ending-support-for-legacy-cloud.html +aliases: +- /blog/ending-support-for-legacy-cloud.html +date: '2018-07-31' +author: Shai Almog +--- + +![Header Image](/blog/ending-support-for-legacy-cloud/looking-forward.jpg) + +Starting this weekend builds sent using the old plugin or an old project will fail. You will need to update the plugin to 4.3 (or 4.0.3 in NetBeans) or newer. This is an important phase in removing App Engine from our build stack and moving to a new system. + +If you are experiencing problems with a project do the following: + + * Right Click the project + + * Select Codename One → Codename One Settings or Codename One Preferences + + * Click Basic + + * Click Update Project Libs in the bottom left side + +### What’s Next? + +After this initial phase we plan to delete the app engine server. This will clean up our legacy system completely. It also means that if you created a Codename One account in the past and haven’t been active your account might vanish. + +In that case you would need to create it all over again. + +### Why are we Doing This? + +The old system based on App Engine is unmaintainable and fundamentally broken. Unfortunately, even basic features on app engine just don’t work so we can’t even keep this running. + +Using our own servers has been liberating and far more powerful. This is a move we should have completed years ago. Once App Engine is completely out of the way we’ll be able to deliver some services we’ve had on the drawing board for years. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Gareth Murfin** — August 8, 2018 at 4:38 am ([permalink](https://www.codenameone.com/blog/ending-support-for-legacy-cloud.html#comment-23987)) + +> Gareth Murfin says: +> +> Awesome cant wait to see the new stuff.. I always assumed app engine was perfect but I dont think ive got around to really using it much. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fending-support-for-legacy-cloud.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/exif-orientation-automatic-captured-image-rotation.md b/docs/website/content/blog/exif-orientation-automatic-captured-image-rotation.md new file mode 100644 index 0000000000..91db53c242 --- /dev/null +++ b/docs/website/content/blog/exif-orientation-automatic-captured-image-rotation.md @@ -0,0 +1,352 @@ +--- +title: Exif Orientation Tag and Smart Downloads +slug: exif-orientation-automatic-captured-image-rotation +url: /blog/exif-orientation-automatic-captured-image-rotation/ +original_url: https://www.codenameone.com/blog/exif-orientation-automatic-captured-image-rotation.html +aliases: +- /blog/exif-orientation-automatic-captured-image-rotation.html +date: '2020-07-02' +author: Shai Almog +--- + +![Header Image](/blog/exif-orientation-automatic-captured-image-rotation/guest-post-1.jpg) + +On some devices, `Capture` APIs return images with the correct orientation, meaning that they do not need to be changed to display correctly; on other devices, they return images with a fixed orientation and an EXIF tag that indicates how they must be rotated or flipped to display correctly. + +More precisely, the Orientation Tag indicates the orientation of the camera with respect to the captured scene and can take a value from 0 to 8, as illustrated on the page [Exif Orientation Tag](http://sylvana.net/jpegcrop/exif_orientation.html). For testing purposes, you can download landscape and portrait images with all possible orientation values from the [EXIF Orientation-flag example images repository](https://github.com/recurser/exif-orientation-examples). + +### What happens if we ignore the Orientation Tag + +Suppose we acquire an image with the following code: + + + Form hi = new Form("Capture Test", BoxLayout.y()); + Button button = new Button("Take Photo"); + ScaleImageLabel photoLabel = new ScaleImageLabel(); + hi.addAll(button, photoLabel); + hi.show(); + + button.addActionListener(l -> { + String photoTempPath = Capture.capturePhoto(); + if (photoTempPath != null) { __**(1)** + try { + String photoStoragePath = "myPhoto.jpg"; + Util.copy(FileSystemStorage.getInstance().openInputStream(photoTempPath), Storage.getInstance().createOutputStream(photoStoragePath)); __**(2)** + photoLabel.setIcon(EncodedImage.create(Storage.getInstance().createInputStream(photoStoragePath), Storage.getInstance().entrySize(photoStoragePath))); __**(3)** + hi.revalidate(); + } catch (IOException ex) { + Log.p("Error after capturing photo", Log.ERROR); + Log.e(ex); + Log.sendLogAsync(); + } + + } + }); + +A few remarks: + +__**1** | `photoTempPath` is `null` if the user has cancelled the photo capture; +---|--- +__**2** | in this case, copying the file from the `FileSystemStorage` temporary folder to a “secure” location in `FileSystemStorage` or `Storage` is not strictly necessary, but it is a good habit that in certain circumstances prevents issues; +__**3** | it is always preferable to use `EncodedImage` when we want to keep the impact on memory low. + +#### Desired result + +On my iPhone, the image is always in portrait orientation: + +![85854279 64b80800 b7b4 11ea 88e2 98a6d57fc09f](/blog/exif-orientation-automatic-captured-image-rotation/85854279-64b80800-b7b4-11ea-88e2-98a6d57fc09f.jpg) + +#### Unwanted result + +This is the case of my Samsung Galaxy, the image was taken in portrait, but shown in a different orientation: + +![85853565 050d2d00 b7b3 11ea 8053 695772ecbfd0](/blog/exif-orientation-automatic-captured-image-rotation/85853565-050d2d00-b7b3-11ea-8053-695772ecbfd0.jpg) + +#### Solving This Problem + +All it takes is a small change to the code to solve this issue. + +Just replace: + + + String photoStoragePath = "myPhoto.jpg"; + Util.copy(FileSystemStorage.getInstance().openInputStream(photoTempPath), Storage.getInstance().createOutputStream(photoStoragePath)); + photoLabel.setIcon(EncodedImage.create(Storage.getInstance().createInputStream(photoStoragePath), Storage.getInstance().entrySize(photoStoragePath))); + +with: + + + String photoSafePath = FileSystemStorage.getInstance().getAppHomePath() + "/myPhoto.jpg"; __**(1)** + Image img = Image.exifRotation(photoTempPath, photoSafePath, 1000); __**(2)** + photoLabel.setIcon(img); __**(3)** + +__**1** | In this case, we have to use `FileSystemStorage` rather than `Storage` due to a limitation of the `exifRotation` API, which maybe will be solved in the future; +---|--- +__**2** | the third parameter is optional, but as explained in the [exifRotation Javadoc](http://www.codenameone.com/javadoc/com/codename1/ui/Image.html#exifRotation-java.lang.String-java.lang.String-int-), the rotation of a high-resolution image is very inefficient, it is better to set the maximum size (width or height) that the image can assume, in this case 1000px, to obtain a significant advantage in processing time on less performing devices; +__**3** | note that the instance of the `Image` object returned by `exifRotation` is an `EncodedImage`, to keep the impact on memory low. + +#### Final result + +On my iPhone the result is the same (as expected), while on my Android, taking the same photo, I get: + +![85862326 e82c2600 b7c1 11ea 9135 657f2a0eead7](/blog/exif-orientation-automatic-captured-image-rotation/85862326-e82c2600-b7c1-11ea-9135-657f2a0eead7.jpg) + +This is the desired result. As a final note, I mention the [Image.getExifOrientationTag](http://www.codenameone.com/javadoc/com/codename1/ui/Image.html#getExifOrientationTag-java.lang.String-) API which allows you to get the EXIF orientation tag of an image, if available. + +### Network error resistant downloads with automatic resume + +When we download a big file, such as a high-resolution image or a video, there are problems that can prevent the download from finishing: + + * The user moves the app to the background or external conditions (such as a phone call) move the app to the background; + + * The operating system enters power saving mode; + + * The Internet connection is lost or any other network error interrupts the download. + +A server-side error may also occur, but this cannot be resolved client-side. All the other circumstances mentioned above can, provided that the server supports partial downloads via HTTP headers. Fortunately, this is a feature available by default on most common servers (such as Apache or Spring Boot). Almost all download managers allow to resume interrupted downloads, so I thought it was important to add such a feature to Codename One. + +#### The solution + +THe new API [Util.downloadUrlSafely](https://www.codenameone.com/javadoc/com/codename1/io/Util.html#downloadUrlSafely-java.lang.String-java.lang.String-com.codename1.util.OnComplete-com.codename1.util.OnComplete-) safely download the given URL to the `Storage` or to the `FileSystemStorage`. + +This method is resistant to network errors and capable of resume the download as soon as network conditions allow and in a completely transparent way for the user. + +#### Server requirements + +The server must correctly return the `Content-Length` header and it must supports partial downloads. + +#### Global network error handling requirements + +In the global network error handling, there must be an automatic `.retry()` of the `ConnectionRequest` in the case of a network error. + +I think the best way to show the use of this API is an actual complete example, which you can try as it is in the Simulator and on real devices: + + + public class MyApplication { + + private Form current; + private Resources theme; + + public void init(Object context) { + // use two network threads instead of one + updateNetworkThreadCount(2); + + theme = UIManager.initFirstTheme("/theme"); + + // Enable Toolbar on all Forms by default + Toolbar.setGlobalToolbar(true); + + // Pro only feature + Log.bindCrashProtection(true); + + // Manage both network errors (connectivity issues) and server errors (codes different from 2xx) + addNetworkAndServerErrorListener(); + } + + public void start() { + if(current != null){ + current.show(); + return; + } + + String url = "https://www.informatica-libera.net/video/AVO_Cariati_Pasqua_2020.mp4"; // 38 MB + + Form form = new Form("Test Download 38MB", BoxLayout.y()); + Label infoLabel = new Label("Starting download..."); + form.add(infoLabel); + + try { + Util.downloadUrlSafely(url, "myHeavyVideo.mp4", (percentage) -> { + // percentage callback + infoLabel.setText("Downloaded: " + percentage + "%"); + infoLabel.repaint(); + }, (filename) -> { + // file saved callback + infoLabel.setText("Downloaded completed"); + int fileSizeMB = Storage.getInstance().entrySize(filename) / 1048576; + form.add("Checking files size: " + fileSizeMB + " MB"); + form.revalidate(); + }); + } catch (IOException ex) { + Log.p("Error in downloading: " + url); + Log.e(ex); + form.add(new SpanLabel("Error in downloading:n" + url)); + form.revalidate(); + } + + form.show(); + + + } + + public void stop() { + current = getCurrentForm(); + if(current instanceof Dialog) { + ((Dialog)current).dispose(); + current = getCurrentForm(); + } + } + + public void destroy() { + } + + private void addNetworkAndServerErrorListener() { + // The following way to manage network errors is discussed here: + // https://stackoverflow.com/questions/61993127/distinguish-between-server-side-errors-and-connection-problems + addNetworkErrorListener(err -> { + // prevents the event from propagating + err.consume(); + + if (err.getError() != null) { + // this is the case of a network error, + // like: java.io.IOException: Unreachable + Log.p("Error connectiong to: " + err.getConnectionRequest().getUrl(), Log.ERROR); + // maybe there are connectivity issues, let's try again + ToastBar.showInfoMessage("Reconnect..."); + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + err.getConnectionRequest().retry(); + } + }, 2000); + } else { + // this is the case of a server error + // logs the error + String errorLog = "REST ERRORnURL:" + err.getConnectionRequest().getUrl() + + "nMethod: " + err.getConnectionRequest().getHttpMethod() + + "nResponse code: " + err.getConnectionRequest().getResponseCode(); + if (err.getConnectionRequest().getRequestBody() != null) { + errorLog += "nRequest body: " + err.getConnectionRequest().getRequestBody(); + } + if (err.getConnectionRequest().getResponseData() != null) { + errorLog += "nResponse message: " + new String(err.getConnectionRequest().getResponseData()); + } + if (err.getConnectionRequest().getResponseErrorMessage() != null) { + errorLog += "nResponse error message: " + err.getConnectionRequest().getResponseErrorMessage(); + } + Log.p(errorLog, Log.ERROR); + + Log.sendLogAsync(); + ToastBar.showErrorMessage("Server Error", 10000); + } + }); + } + + } + +#### Safe Uploads? + +Implementing uploads with the same features (network error resistance and automatic resume) is more complex, because in this case we do not have a reference standard available by default on the most common servers. + +Moreover, the possibility of partial uploads assumes that, after a network error, the server must keep the partially uploaded file and there are no ambiguities about which client has partially uploaded which file. + +Applications such as Dropbox, Google Drive, OwnCloud and similar use specific internal standards. As far as I’m concerned, I’m almost completed deploying my own client-server solution to allow secure, network error-resistant with automatic resume uploads with Codename One and Spring Boot. This solution, however, is too specific to be included in the Codename One API and, anyway, I still have to do a lot of testing to make sure it works as it should. I’ll possibly publish a tutorial about it when it is finished. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Javier Anton** — July 3, 2020 at 10:45 pm ([permalink](https://www.codenameone.com/blog/exif-orientation-automatic-captured-image-rotation.html#comment-24283)) + +> Really useful stuff. Just wondering, the safe download always requires the app to be in fg to finish, right? I mean, the download won’t finish if the app goes into bg and never comes back? And my second question is: does the download effectively pause when the app is in bg? Thx +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fexif-orientation-automatic-captured-image-rotation.html) + + +### **Shai Almog** — July 4, 2020 at 4:50 am ([permalink](https://www.codenameone.com/blog/exif-orientation-automatic-captured-image-rotation.html#comment-24284)) + +> This uses background fetch to download in the background so download continues automatically when the device is backgrounded. Normally when a device is sent to background a download will stop in this case it’s supposed to continue. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fexif-orientation-automatic-captured-image-rotation.html) + + +### **Francesco Galgani** — July 5, 2020 at 5:46 am ([permalink](https://www.codenameone.com/blog/exif-orientation-automatic-captured-image-rotation.html#comment-24285)) + +> I’m afraid there’s been a misunderstanding. As I wrote: “This method is resistant to network errors and capable of resume the download as soon as network conditions allow and in a completely transparent way for the user. This is regardless of whether the download continues or not when the app goes in background: if the operating system stops the download when the app goes in background, it will automatically resume when the app goes back in foreground, otherwise it will continue in background. More specifically, usually (but not necessarily always) the download will continue in the background on Android, while it will “pause” on iOS. Without this method, when the app goes into the background the download can be “killed” without finish, with this method the download will be restored to where it came from when the app returns to foreground. In this sense, it is normal to expect the download to end when the app is returned to foreground, although in some cases (such as Android) it may continue and complete in the background. Backgroundfetch is therefore not used. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fexif-orientation-automatic-captured-image-rotation.html) + + +### **Shai Almog** — July 5, 2020 at 6:17 am ([permalink](https://www.codenameone.com/blog/exif-orientation-automatic-captured-image-rotation.html#comment-24287)) + +> Shai Almog says: +> +> Thanks for the clarification. I didn’t recall the PR exactly but recalled our stackoverflow discussion. +> What about adding something closer to what was done in stackoverflow with background fetch? +> +> Maybe as a secondary API we can add to the stop() call? E.g. convertOngoingDownloads()? +> +> I’m guessing we would need a DownloadManager sort of API to do something like that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fexif-orientation-automatic-captured-image-rotation.html) + + +### **Francesco Galgani** — July 5, 2020 at 7:17 am ([permalink](https://www.codenameone.com/blog/exif-orientation-automatic-captured-image-rotation.html#comment-24288)) + +> [Francesco Galgani](https://lh6.googleusercontent.com/-4K0ax_DVJf4/AAAAAAAAAAI/AAAAAAAAAAA/AMZuuckEd1kcni0y8k6NMzNtxwOCEPatQQ/photo.jpg) says: +> +> I will try to study this problem to improve this API, the problem is that “background fetch” is not usable for heavy downloads. I quote: +> +> “You only have seconds to operate when doing a background fetch — the consensus figure is a maximum of 30 seconds, but shorter is better. If you need to download large resources as part of the fetch, this is where you need to use URLSession‘s background transfer service.” fonte: +> +> I don’t know this “URLSession‘s background transfer service”. Is this something that requires a native interface? Do you have any suggestions for me? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fexif-orientation-automatic-captured-image-rotation.html) + + +### **Shai Almog** — July 6, 2020 at 5:35 am ([permalink](https://www.codenameone.com/blog/exif-orientation-automatic-captured-image-rotation.html#comment-24290)) + +> Shai Almog says: +> +> Not sure. I’ll have to look into that too. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fexif-orientation-automatic-captured-image-rotation.html) + + +### **Javier Anton** — July 6, 2020 at 6:49 am ([permalink](https://www.codenameone.com/blog/exif-orientation-automatic-captured-image-rotation.html#comment-24289)) + +> [Javier Anton](https://lh3.googleusercontent.com/a-/AAuE7mDRjHkEvAZNXquh9p7Oo00ey1yOwNzZ0SrFwD0IVA) says: +> +> I hope you get this sorted – was on my todo list too. You can do iOS bg fetch and just catch whether the OS kills the download. The issue is that you will need to run it in a native interface and provide a callback static method somewhere in your java code. Perhaps you could also use some other method to notify your main thread (NSUserDefaults or writing a persisted file). I’m not sure which is best for your implementation. Good luck! 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fexif-orientation-automatic-captured-image-rotation.html) + + +### **Javier Anton** — August 13, 2020 at 3:21 pm ([permalink](https://www.codenameone.com/blog/exif-orientation-automatic-captured-image-rotation.html#comment-24319)) + +> [Javier Anton](https://lh3.googleusercontent.com/a-/AAuE7mDRjHkEvAZNXquh9p7Oo00ey1yOwNzZ0SrFwD0IVA) says: +> +> Wow. I was just testing with some photos my wife had taken with her pro camera and noticed that some pictures that showed up properly in the OS were being rotated by the Simulator. I then remembered this post, decided to see if it would fix this and… voila! Thanks for this Francesco, really great stuff +> One question I have is: if I don’t set a maximum px in the 3rd parameter of exifRotation, will it make it harder for images that need rotating, or will it make it harder for all images? +> Edit: this will mistakenly rotate 90 degrees to the right images captured by my Galaxy A10 camera +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fexif-orientation-automatic-captured-image-rotation.html) + + +### **Javier Anton** — August 13, 2020 at 4:15 pm ([permalink](https://www.codenameone.com/blog/exif-orientation-automatic-captured-image-rotation.html#comment-24320)) + +> [Javier Anton](https://lh3.googleusercontent.com/a-/AAuE7mDRjHkEvAZNXquh9p7Oo00ey1yOwNzZ0SrFwD0IVA) says: +> +> Another question I have is: why use the ImageIO.save so much? A lot of the operations can be done without needing to re-save the image to a different file. Am I missing something? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fexif-orientation-automatic-captured-image-rotation.html) + + +### **Shai Almog** — August 14, 2020 at 4:33 am ([permalink](https://www.codenameone.com/blog/exif-orientation-automatic-captured-image-rotation.html#comment-24322)) + +> Shai Almog says: +> +> If rotatedImage url is null it won’t save the rotated image to a file so there’s no need for that. Notice that it always returns an encoded image so there will always be an encoder overhead. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fexif-orientation-automatic-captured-image-rotation.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/facebook-better-input-improving-community-support.md b/docs/website/content/blog/facebook-better-input-improving-community-support.md new file mode 100644 index 0000000000..f5a1557226 --- /dev/null +++ b/docs/website/content/blog/facebook-better-input-improving-community-support.md @@ -0,0 +1,155 @@ +--- +title: Facebook, Better Input & Improving Community Support +slug: facebook-better-input-improving-community-support +url: /blog/facebook-better-input-improving-community-support/ +original_url: https://www.codenameone.com/blog/facebook-better-input-improving-community-support.html +aliases: +- /blog/facebook-better-input-improving-community-support.html +date: '2013-11-19' +author: Shai Almog +--- + +![Header Image](/blog/facebook-better-input-improving-community-support/facebook-better-input-improving-community-support-1.png) + + + + + +![Facebook Login](/blog/facebook-better-input-improving-community-support/facebook-better-input-improving-community-support-1.png) + + + + +Facebook has changed the rules yet again, this time related to logging in to Facebook from 3rd party applications. Up until now we used the web based OAuth approach for logging into Facebook since that allowed us to keep the same implementation across Android, iOS, Blackberry etc. without changing anything. However, the new Facebook 2 factor authentication is a very complex process and Facebook really went overboard with a very elaborate mobile API. + + +So we had no choice but to integrate the native Facebook SDK when necessary (you will not “pay for it” if you don’t use it). This is currently in beta so the API is very likely to change which is why we are not docume + +nting it yet by writing a proper tutorial. This isn’t essential yet since the current Facebook API is still working and well documented. If you would like to take a look its within the social package, we would appreciate feedback, ideas and use cases. + + +On a different issue the just released version of the plugin addresses some issues with text input in the simulator (and Java SE port) + +related to +[ +this issue +](http://code.google.com/p/codenameone/issues/detail?id=957) +. The crux of the issue lies in the usage of the highly broken AWT text field. Up until now we wanted to transition to the Swing text field but had serious flickering issues. I was finally able to resolve these issues in the latest version which will hopefully improve the simulators behavior in this regard. + + +We also made some changes to reduce the flickering of the native Webkit when interacting with JavaFX, this is a huge step towards producing a robust desktop app port in the future. + + +We had a lot of complaints and issues with the Google groups support forums, this is a huge problem but in the past most other solutions were either high maintenance or SPAM magnets. While we will probably keep and support the Google groups until Google actually kills the product (which might be next week with those guys) we are considering a Facebook group as a secondary support option. + + + +However, we will only do that if there is community interest in this so if you would like a Facebook group and promise to join then just vote below. + + + +* * * + + +Loading… + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — November 20, 2013 at 12:57 pm ([permalink](https://www.codenameone.com/blog/facebook-better-input-improving-community-support.html#comment-22010)) + +> Anonymous says: +> +> Can you elaborate on this line: (you will not “pay for it” if you don’t use it) +> +> Any idea on how much this will cost to use? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-better-input-improving-community-support.html) + + +### **Anonymous** — November 20, 2013 at 12:59 pm ([permalink](https://www.codenameone.com/blog/facebook-better-input-improving-community-support.html#comment-24254)) + +> Anonymous says: +> +> In size not financially 😉 +> +> It won’t increase your app size by bundling in the Facebook SDK if you don’t use it. I should be clearer on those things. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-better-input-improving-community-support.html) + + +### **Anonymous** — November 20, 2013 at 11:51 pm ([permalink](https://www.codenameone.com/blog/facebook-better-input-improving-community-support.html#comment-21746)) + +> Anonymous says: +> +> Um, believe it or not – not every developer has a facebook account but almost all of them are in linkedin – linkedin groups may make more sense. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-better-input-improving-community-support.html) + + +### **Anonymous** — November 21, 2013 at 2:46 am ([permalink](https://www.codenameone.com/blog/facebook-better-input-improving-community-support.html#comment-21789)) + +> Anonymous says: +> +> We already have a LinkedIn group that isn’t very active. Its sort of a control to see whether a potential Facebook group will see more activity. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-better-input-improving-community-support.html) + + +### **Anonymous** — November 21, 2013 at 5:27 am ([permalink](https://www.codenameone.com/blog/facebook-better-input-improving-community-support.html#comment-21804)) + +> Anonymous says: +> +> I have all Facebook domains mapped to 0.0.0.0 in my hosts file because I especially DON’T want those buggers tracking me all over the Net. +> +> Google Groups seem to work OK. +> +> You could always use Usenet 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-better-input-improving-community-support.html) + + +### **Anonymous** — November 23, 2013 at 5:17 am ([permalink](https://www.codenameone.com/blog/facebook-better-input-improving-community-support.html#comment-22055)) + +> Anonymous says: +> +> I know spam is an issue when creating a forum. It would be nice to have things more organized with sub sections, especially if it was accessible using the Tapatalk app. Google Groups mobile website is an absolute pain and I enjoy reading while away from my computer. +> +> It may be plausible to have a password generated from within codenameone settings in the IDE or something along those lines to access the forum, that way people who are actually using codenameone would get the password as that is the majority of users in the forum anyway, that may eliminate a lot of spamming. That way you could have a real forum site like XDA with multiple sections and would be much easier to find already asked and answered questions. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-better-input-improving-community-support.html) + + +### **Anonymous** — November 23, 2013 at 5:29 am ([permalink](https://www.codenameone.com/blog/facebook-better-input-improving-community-support.html#comment-21873)) + +> Anonymous says: +> +> Actually Google groups introduced the ability to use categories which is pretty similar to proper sections. That would be very useful. +> +> However, they neglected a proper migration path so if we add categories all our existing posts mostly disappear and you won’t see them under any category. +> +> An admin can start going over messages and manually categorizing them one by one, however that’s obviously tedious and painful. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-better-input-improving-community-support.html) + + +### **Anonymous** — November 27, 2013 at 8:55 am ([permalink](https://www.codenameone.com/blog/facebook-better-input-improving-community-support.html#comment-21891)) + +> Anonymous says: +> +> Go for project management system like Redmine. Then everything will be in one place: issue tracking, wiki, forum, etc. Easy to make relations, and build valuable documentation extended by tips & trick shared by community on forum. Keeping those things separated and using multiple providers does not help… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-better-input-improving-community-support.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/facebook-clone-slow-landing.md b/docs/website/content/blog/facebook-clone-slow-landing.md new file mode 100644 index 0000000000..661dde35f4 --- /dev/null +++ b/docs/website/content/blog/facebook-clone-slow-landing.md @@ -0,0 +1,98 @@ +--- +title: Facebook Clone Slow Landing +slug: facebook-clone-slow-landing +url: /blog/facebook-clone-slow-landing/ +original_url: https://www.codenameone.com/blog/facebook-clone-slow-landing.html +aliases: +- /blog/facebook-clone-slow-landing.html +date: '2018-04-29' +author: Shai Almog +--- + +![Header Image](/blog/facebook-clone-slow-landing/build-real-world-full-stack-mobile-apps-in-java.jpg) + +I mentioned before that I’m really behind on the Facebook Clone module but at least I was able to [release the first few lessons](https://codenameone.teachable.com/p/build-real-world-full-stack-mobile-apps-in-java) by today which makes it fit into an April deadline. I’ll try to release new lessons every day so we can do have the full module out before the end of May. At that point I’ll release two new modules during June. + +The new Facebook Clone is similar to the Uber clone in some regards and also very different: + + * I didn’t do a “pixel perfect” clone – Facebook is too messy to clone properly + + * I used CSS instead of the designer tool – it’s easier to tech CSS as I can go over code instead of screenshots + + * I put more logic in the server and tried to make the app more “real” + +The things I kept in place are: + + * MySQL – it’s a pretty good database and easy to work with when compared to no-SQL solutions. In fact it’s also WAY faster than most of them for real world loads. I see a lot of startups buying into the no-SQL hype which makes sense for some cases but usually doesn’t + + * Spring Boot – I chose to use version 2.0 which went GA by now. It’s a great option for Java developers! + +One of the things I’d love to do is port this to Kotlin, maybe as one of the extra modules to be discussed later. + +I’ll leave you with a couple of screenshot studies of the original vs. clone: + +![Original vs. Clone Portrait](/blog/facebook-clone-slow-landing/login-screen-original-vs-clone-portrait.png) + +Figure 1. Original vs. Clone Portrait + +![Original vs. Clone Landscape](/blog/facebook-clone-slow-landing/login-screen-original-vs-clone-landscape.png) + +Figure 2. Original vs. Clone Landscape +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **beck** — April 30, 2018 at 5:04 pm ([permalink](https://www.codenameone.com/blog/facebook-clone-slow-landing.html#comment-23845)) + +> Are these clones (uber & fb clone) apk files available so that we can test them in devices before diving into the courses? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-clone-slow-landing.html) + + +### **Shai Almog** — May 1, 2018 at 4:28 am ([permalink](https://www.codenameone.com/blog/facebook-clone-slow-landing.html#comment-23863)) + +> No. That would be legally problematic. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-clone-slow-landing.html) + + +### **Tommy Mogaka** — May 1, 2018 at 6:03 am ([permalink](https://www.codenameone.com/blog/facebook-clone-slow-landing.html#comment-23838)) + +> Tommy Mogaka says: +> +> In the fb clone, will you also do the messenger part? I mean that little chat widget. That would be really cool… +> Keep up the goodwork! cn1 is truly a solid development tool, best of both worlds i.e. cross-platform and native. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-clone-slow-landing.html) + + +### **Shai Almog** — May 2, 2018 at 2:25 pm ([permalink](https://www.codenameone.com/blog/facebook-clone-slow-landing.html#comment-23953)) + +> Shai Almog says: +> +> No. +> The next app that’s currently scheduled for August-September would be a WhatsApp clone so this should probably cover that aspect. See [https://www.codenameone.com…]() +> Thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-clone-slow-landing.html) + + +### **Francesco Galgani** — May 4, 2018 at 1:28 pm ([permalink](https://www.codenameone.com/blog/facebook-clone-slow-landing.html#comment-23632)) + +> Francesco Galgani says: +> +> Dear Shai, +> thank you for your work 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffacebook-clone-slow-landing.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/facebook-publish-android-localization.md b/docs/website/content/blog/facebook-publish-android-localization.md new file mode 100644 index 0000000000..30379e1e46 --- /dev/null +++ b/docs/website/content/blog/facebook-publish-android-localization.md @@ -0,0 +1,74 @@ +--- +title: Facebook Publish & Android Localization +slug: facebook-publish-android-localization +url: /blog/facebook-publish-android-localization/ +original_url: https://www.codenameone.com/blog/facebook-publish-android-localization.html +aliases: +- /blog/facebook-publish-android-localization.html +date: '2014-05-25' +author: Shai Almog +--- + +![Header Image](/blog/facebook-publish-android-localization/facebook-publish-android-localization-1.png) + + + + + +![Picture](/blog/facebook-publish-android-localization/facebook-publish-android-localization-1.png) + + + + +The Facebook native SDK for iOS and Android is difficult. It layers a great deal of complex permissions and concepts that seem obvious for engineers in Facebook but not so obvious for the casual observer. In the past Facebook allowed you to just request a write permission and you would receive such a permission, however recent SDK’s force you to request a read only permission which you then need to elevate to a write permission. + + + + + +Not the most intuitive approach although understandable in terms of data security, + +but it is badly implemented and to make matters worse its horribly broken in some SDK versions (Chen spent the day just because the version we used happened to be such a version). Regardless, we now have the ability to elevate Facebook permissions as part of the Facebook connect API in the social package. You just need to ask for publish permissions and once the callback is invoked with a success message you can write to the Facebook wall. + + + + +A simpler approach is usually to just use the Share button which requires no special permissions so if you just want to share something we would recommend doing that. It maps to native iOS/Android functionality and is pretty powerful since it can map to Twitter and other apps installed on the device too. + + + + +On a different subject, localization is a pretty easy task in Codename One thanks to the +[ +i18n support +](/how-do-i---localizetranslate-my-application-apply-i18nl10n-internationalizationlocalization-to-my-app.html) +builtin to our tools. Our i18n tools are unique since they don’t require you to implement anything in the code and you can instantly start localizing without wide sweeping changes. However, the Android APK doesn’t detect our localization as part of your application and might incorrectly assume the APK contains a single language. To combat that we are introducing the build argument: android.locales=local;local;locale + + +Where you can specify the supported languages for the APK, locale can be any 2 letter language code such as fr for French, en for English etc. Notice that these are standard combinations based on an iso standard. + + + + +We also allow specifying the default language of a Windows Phone app using the win.locale=en-US build argument where you can customize the locale to any one you would like. + + + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.md b/docs/website/content/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.md new file mode 100644 index 0000000000..e33a28adc9 --- /dev/null +++ b/docs/website/content/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.md @@ -0,0 +1,319 @@ +--- +title: Fractional Padding/Margin, Rounded Border, Ripple, Caps, Google Connect +slug: factional-padding-margin-rounded-border-ripple-caps-google-connect +url: /blog/factional-padding-margin-rounded-border-ripple-caps-google-connect/ +original_url: https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html +aliases: +- /blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html +date: '2017-07-23' +author: Shai Almog +--- + +![Header Image](/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect/new-features-6.jpg) + +We’ve been very busy the past few weeks despite the summer time but August is always problematic, I will personally take some time off from the blog next week and near the end of August. To allow that I want to clear my table from a lot of the features that went into Codename One over the past couple of weeks and didn’t get sufficient or any documentation…​ + +I wrote about some of these features before in the pixel perfect posts but I glossed over them. Some of the other features I didn’t cover at all! + +### Google Plus is Dead + +Even when we wrote the blog posts detailing google plus login we new the end was near for that social network…​ + +Google has pretty much ended support for the old Google+ login API’s and Steve migrated our existing Google+ support to use standard Google account connect. The cool thing is that the integration should now be MUCH easier and can be summed up with: + + * Go to [the Google Developer Portal](https://developers.google.com/mobile/add) + + * Follow the steps to create an App + + * Enable Google Sign-In + + * Download the google-services.json file into your project’s native/android directory + + * Download the GoogleService-Info.plist file into your project’s native/ios directory + +This is the super short version…​ Steve updated the [developer guide section on Google Cconnect](/manual/misc-features.html) with a longer more detailed explanation of the steps. + +### Fractional Padding/Margin + +This is a pretty big feature, currently the only way you can use this is by compiling your own version of the Codename One Designer but it will be around with plugin update 3.7.3 (we don’t have an ETA for that yet but I hope it won’t be too long). + +This essentially means you would be able to use fractions to define padding and margin in the designer UI: + +![Fractions in margin](/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect/fractions-in-margin.png) + +Figure 1. Fractions in margin + +This won’t work for pixels, it will get rounded down. But it should work great for millimeters where 1mm often proved to be too much in newer devices. + +The reason we didn’t have that around sooner is that it requires a deep change to the resource file format which is always a painful nuanced process. We bundled this with another big change to the file format…​ + +### Rethinking Round Rect + +We created `Border` in the LWUIT days and it grew very old. The goals it set out to accomplish were radically different from the ones we have today which is why we created `RoundBorder` when we needed something more expressive. + +`RoundBorder` works great for round and pill shapes but the classic square with rounded corners is still only available in the `Border` class. Normally, this would be enough but there is a lot of nuance we wanted to introduce to that API and a lot that we learned from the `RoundBorder`. So we created a new class [RoundRectBorder](https://www.codenameone.com/javadoc/com/codename1/ui/plaf/RoundRectBorder.html) which allows you to create a round border that’s more refined. Here I adapted the original [RoundBorder](https://www.codenameone.com/javadoc/com/codename1/ui/plaf/RoundBorder.html) sample to work with `RoundRect`: + + + Form hi = new Form("RoundRect", new BorderLayout(BorderLayout.CENTER_BEHAVIOR_CENTER)); + + Button ok = new Button("OK"); + Button cancel = new Button("Cancel"); + + Label loginLabel = new Label("Login", "Container"); + loginLabel.getAllStyles().setAlignment(Component.CENTER); + + Label passwordLabel = new Label("Password", "Container"); + passwordLabel.getAllStyles().setAlignment(Component.CENTER); + + TextField login = new TextField("", "Login", 20, TextArea.ANY); + TextField password = new TextField("", "Password", 20, TextArea.PASSWORD); + Style loginStyle = login.getAllStyles(); + Stroke borderStroke = new Stroke(2, Stroke.CAP_SQUARE, Stroke.JOIN_MITER, 1); + loginStyle.setBorder(RoundRectBorder.create(). + strokeColor(0). + strokeOpacity(120). + stroke(borderStroke)); + loginStyle.setBgColor(0xffffff); + loginStyle.setBgTransparency(255); + loginStyle.setMarginUnit(Style.UNIT_TYPE_DIPS); + loginStyle.setMargin(Component.BOTTOM, 3); + Style passwordStyle = password.getAllStyles(); + passwordStyle.setBorder(RoundRectBorder.create(). + strokeColor(0). + strokeOpacity(120). + stroke(borderStroke)); + passwordStyle.setBgColor(0xffffff); + passwordStyle.setBgTransparency(255); + + + Container box = BoxLayout.encloseY( + loginLabel, + login, + passwordLabel, + password, + GridLayout.encloseIn(2, cancel, ok)); + + Button closeButton = new Button(); + Style closeStyle = closeButton.getAllStyles(); + closeStyle.setFgColor(0xffffff); + closeStyle.setBgTransparency(0); + closeStyle.setPaddingUnit(Style.UNIT_TYPE_DIPS); + closeStyle.setPadding(3, 3, 3, 3); + closeStyle.setBorder(RoundBorder.create().shadowOpacity(100)); + FontImage.setMaterialIcon(closeButton, FontImage.MATERIAL_CLOSE); + + Container layers = LayeredLayout.encloseIn(box, FlowLayout.encloseRight(closeButton)); + Style boxStyle = box.getUnselectedStyle(); + boxStyle.setBgTransparency(255); + boxStyle.setBgColor(0xeeeeee); + boxStyle.setMarginUnit(Style.UNIT_TYPE_DIPS); + boxStyle.setPaddingUnit(Style.UNIT_TYPE_DIPS); + boxStyle.setMargin(4, 3, 3, 3); + boxStyle.setPadding(2, 2, 2, 2); + + hi.add(BorderLayout.CENTER, layers); + + hi.show(); + +![Round rect sample](/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect/round-rect-sample.png) + +Figure 2. Round rect sample + +There are several things we learned from doing the `RoundBorder` that we applied and did differently in `RoundRectBorder`: + + * We use the UIID for the background color that just makes sense. We didn’t do the same for the stroke color/foreground color though. The background should now behave nicely including gradients and images! + + * We use millimeters where it makes sense, so a stroke can be in pixels since a 1 or 2 pixel stoke is something you might need but corner radius is always in millimeters as pixels just don’t fit here + +This can also be customized via the designer tool which is another reason we had to change the resource file format: + +![New rounded rectangle UI in the designer tool](/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect/rounded-rectangle-in-designer-tool.png) + +Figure 3. New rounded rectangle UI in the designer tool + +### Ripple Effect + +The ripple effect is an Android effect that occurs when you press and hold a button. It ripples slightly. + +It’s actually pretty nice and assuring that your touch was intercepted. This effect is implemented in the component level but at the moment it was only turned on for `Button`. Moving forward this will probably be enabled for `MultiButton`, `SpanButton` and other component types. + +Every component has a ripple effect flag now that you can check and toggle via `isRippleEffect()` and `setRippleEffect(boolean)`. In buttons that flag is set from the default state which you can tune via the theme constant `buttonRippleBool` or via the `Button.setButtonRippleEffectDefault(boolean)` method. + +When a component is pressed and it has the ripple effect we keep painting it until it’s released. During that time we draw a translucent black color on top as a growing circle until it fills up the available space. You can customize the behavior of this painting by overriding `paintRippleOverlay(Graphics g, int x, int y, int position)`. I wouldn’t recommend doing that unless you are going for a completely unique application look. + +### Button Caps + +One of the more controversial changes we made was to upcase all the button text by default for Android. You can disable that behavior by using the theme constant `capsButtonTextBool` and set it to false or invoking `Button.setCapsTextDefault(false)`. + +Android buttons should be upper case but iOS should have correct casing. This is very obvious when looking at iOS/Android UI’s critically. If you want to leave the global behavior but have case correctness for one individual button you can do this by invoking `Button.setCapsText(boolean)`. + +In order to reduce the impact of this behavior we didn’t apply it to every `Button` in existence even when it’s turned on. This only applies to `Dialog` buttons and buttons with the UIID’s `Button` or `RaisedButton`. That means that if you have a custom button UIID you will need to explicitly call `setCapsText(Button.isCapsTextDefault())` to force this feature on for that `Button`. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Gareth Murfin** — July 24, 2017 at 10:26 pm ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-23500)) + +> Great update, it is a joy to see such leaps and bounds in functionality, congrats. Keep up the good work guys!.. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + + +### **Nick Koirala** — July 25, 2017 at 2:20 am ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-23204)) + +> I like the ripple effect but it seems like its in slow motion compared to the material design ripple effect, how is the speed controlled? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + + +### **Shai Almog** — July 25, 2017 at 4:34 pm ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-23564)) + +> Right now it’s hardcoded. I looked at several implementations and each one looked very different so I eyeballed it. I’ll try to think of the right way to customize this, can you file an RFE? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + + +### **Nick Koirala** — August 10, 2017 at 3:10 am ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-23529)) + +> Nick Koirala says: +> +> Button caps is a bit messy. If you use the GUI Builder it sets the text before setting the UIID so you get caps regardless of UIID (because its ‘Button’ when the text is set) so you can’t use a custom UIID to manage this if you wanted smaller buttons in a lowercase style or whatever. If you did want them caps but then set the text later with setText() it’ll be whatever case you set it as and the UIID has been set by then. +> +> Also if you do use a custom UIID on a lot of buttons and want them in caps you need to call setCapsText(Button.isCapsTextDefault()) on each instance as its not an option you can toggle on all buttons at once or at a UIID level. So it requires additional code throughout simply to achieve what this is setting out to do (Caps on one platform and not on others). +> +> I’m not sure why this system is needed at all really, its not hard to implement if you do need it, not hard to turn off if you don’t want it, but if you do want caps on buttons on Android this system produces inconsistent behaviour. +> +> This is a change that has an effect on the UI of apps currently in development – changing the style between builds, with the default set to be the new behaviour. I don’t think that should be the way that updates like this are rolled out. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + + +### **Shai Almog** — August 10, 2017 at 5:17 am ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-23737)) + +> Shai Almog says: +> +> Thanks for the feedback. I agree we need a better way to indicate supported/unsupported UIID’s. Any suggestions? +> +> I chose the default to work with specific UIID’s since button is so widespread that doing it for everything might have been even more disruptive. +> +> The goal is to have a default “native” behavior that’s “seamless”. Android does the same thing by styling buttons as all caps by default so this seems like the right thing to do. +> +> In that sense a better place to put this would have been the style text effects property, I chose not to do that for performance reasons but I’m not sure if that was the right call. +> +> I agree that launching something and flipping a default is problematic but leaving something that’s wrong is problematic too. I asked in the original post for suggestions on how we can move things forward without disruption and got crickets… +> +> It’s pretty easy to say “don’t release it like this” without suggesting a better way. We asked this multiple times and suggestions effectively amounted to don’t change the product. Those conflict with the notion of moving it forward: +> +> – Leave it off by default – that’s a bad suggestion. It’s off then no one uses it and it might as well not exist +> +> – Release in a specific time or with huge/many announcements – We did an announcement and included a big “compatibility warning”. Distributed as much as we reasonably can… In the past we did bigger/longer term announcements for similar changes (gradle migration, xcode migration etc). People don’t read these. It’s just a waste of time that delays forward progress +> +> – Add ability to disable this easily – we have that +> +> – Add ability not to be affected – we did this right after the 3.7 release so a versioned build would be relevant and allow you not to feel such issues +> +> We have many changes like this coming so if you have a suggestion I’m listening… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + + +### **Nick Koirala** — August 10, 2017 at 6:39 am ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-21524)) + +> Nick Koirala says: +> +> I think it should apply to buttons regardless of style – obviously still with the options to turn it off. Using UIID to signal if it applies or not is a good idea, but only if it was part of the style definition which no doubt adds a whole lot more complexity. +> +> I didn’t think it was too important one way or the other if button labels were in caps on Android – most of my apps aren’t really trying to look native but rather mostly similar but familiar on each platform – but once I suddenly had an Android build that had some buttons in caps and some not it was a mess that needed to be resolved. As the GUI Builder puts them all in caps regardless of UIID but calls to setText may not it took some tidying to put right. In this case I DID go for having all buttons in uppercase on Android mainly because your post highlighted that it was more correct but due to the implementation it was more work than just setting the theme constant and putting it back to proper case. +> +> Obviously changes and progress of your product can’t be a democratic progress where everyone’s view is counted and people are happy all the time, but forced changes especially ones that alter the look and feel of the app are not certainly not desirable. I’d suggest new features or performance enhancements get rolled out straight away as you currently do. But changes to default behaviour do need to be signaled a bit better and they need to be solid when they are made the default. +> +> I check the blog every day, to the point I was worried about you when you went on vacation :). I’ve used the options for the newVM and gradle builds when they were rolled out. It was great to be able to build projects consistently with the old settings while these changes were coming in and also use the new settings for new projects. +> +> So my preference is that any changes to default have some period where the original behaviour is default. I understand why you don’t like this as it makes the roll out more difficult with less initial adoption but its a balancing act between letting developers complete their projects, updating and providing new functionality to your core, and using your developers as guinea pigs on new functionality and disrupting their own progress. +> +> I’m not sure how difficult it is to manage changes with the build process at your end – big red warnings in the console output or something. I’m thinking of the way methods are deprecated before being removed from APIs allows progress and updates while making developers be aware of the upcoming changes and giving them the opportunity to adapt on their schedules. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + + +### **Shai Almog** — August 11, 2017 at 7:21 am ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-23626)) + +> Shai Almog says: +> +> The GUI builder uppercasing is indeed something we need to fix. You are referring to the new GUI builder right? +> +> I’ve committed a fix for this and will push it into today’s update. +> +> If we were building a new product from scratch I would uppercase all buttons or put this into the style both of which I agree are better choices. The problem is that both would disrupt too many production apps in unpredictable ways. I’d also want this to apply correctly for multibuttons, span buttons etc. as we move forward and none of them are buttons. So the “right thing” here is a bit “off”. +> +> I’m actually all for a democracy here, even in a democracy there is a PM or President who navigates but can’t do stuff congress disagrees with. Unfortunately I made a post about this which got literally zero comments. Maybe it’s the writing that’s too verbose but I’m guessing it’s just hard for people to understand until they see something that impacts their app. +> +> In the past we did a lot of staged rollouts like the ones you describe and the results were the exact same thing. Everyone ignored the rollout until we flipped the default. That made releasing harder as we already moved forward on several fronts and it was harder to revert. +> +> Other tools take the opposite approach to us where developers work on the feature release e.g. 3.7.0 (like our versioned builds) and get an update once every few months that’s really disruptive. Some developers stay on older versions which makes their support process much harder. I don’t think that’s better. Every developer works on a different version and we don’t get immediate feedback for features/bugs so by the time something reaches you guys we forgot why we did something or what we did. Smaller features vanish with big releases like that and it’s harder on everyone. +> +> Using some notification on changes in the build server makes sense for changes like the 64 bit migration (we did that and people still ignore it) but for something like this it doesn’t really make sense. It might seem like a huge disruptive change to you but the fact is that except for a few people who had a problem with it, this went mostly unnoticed by the community at large. That’s a good thing, changes like this should be mostly seamless. +> +> Notice that when Google or Apple update their OS’s a native app that’s already on the device will break and/or change its look. With Codename One updates you will only see it for your builds not for production apps so we are better off than standard native apps in that sense. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + + +### **Diamond** — August 22, 2017 at 9:13 am ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-23677)) + +> Diamond says: +> +> I love the fractional padding and margin values. Will this be available in code too? +> +> Like having: +> cmp.getAllStyles().setPaddingTop(2.6); +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + + +### **Shai Almog** — August 22, 2017 at 1:20 pm ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-24210)) + +> Shai Almog says: +> +> Right now we have only the setPadding(top, bottom, left, right) that accepts float values (not double like your code does). We don’t have the floating point equivalents for setPaddingTop/Bottom/Left/Right. Mostly due to laziness. Notice that if you want to submit a PR you will need to add new methods and can’t change the existing method signature from int to float as that will break binary compatibility. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + + +### **Diamond** — August 22, 2017 at 2:10 pm ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-21530)) + +> Diamond says: +> +> I’ve added the methods. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + + +### **Thomas** — March 22, 2018 at 8:00 pm ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-23829)) + +> Thomas says: +> +> Is there a way to use rounded borders from the new GUI builder? In the old builder there was a border wizard that allowed to create custom borders by generating a 9 components image but I could not find it in the new GUI builder and the RoundRectBorder type is not offered as an option (only the “round” border type, that seems to map to RoundBorder exists in the border editor of the new GUI builder) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + + +### **Shai Almog** — March 23, 2018 at 2:42 am ([permalink](https://www.codenameone.com/blog/factional-padding-margin-rounded-border-ripple-caps-google-connect.html#comment-23757)) + +> Shai Almog says: +> +> When you edit a style in the GUI builder it’s meant more as a small override over the default theming. 9-piece borders are a bit more complex as they require image generation and this can get tricky if you have multiple variants. +> RoundRectBorder is relatively new and came to be in parallel to this feature. Can you please file an issue on that? It should go into the style UI too. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffactional-padding-margin-rounded-border-ripple-caps-google-connect.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/fail-fast-margin-padding-performance.md b/docs/website/content/blog/fail-fast-margin-padding-performance.md new file mode 100644 index 0000000000..6375be326a --- /dev/null +++ b/docs/website/content/blog/fail-fast-margin-padding-performance.md @@ -0,0 +1,140 @@ +--- +title: Fail Fast & Margin/Padding Performance +slug: fail-fast-margin-padding-performance +url: /blog/fail-fast-margin-padding-performance/ +original_url: https://www.codenameone.com/blog/fail-fast-margin-padding-performance.html +aliases: +- /blog/fail-fast-margin-padding-performance.html +date: '2016-11-22' +author: Shai Almog +--- + +![Header Image](/blog/fail-fast-margin-padding-performance/phone-espresso.jpg) + +One of the frustrating parts in Codename One is builds failing in the cloud, the expectation is that a build that passes +locally would pass in the cloud and that is something we strive to have at all times. One of the more common +failures for new developers is due to refactoring of the main class or changing the signatures of the methods +e.g. adding a throws clause to `start()`. + +Starting with the next library update when you run a project it will use the main class defined in `codenameone_settings.properties` +and not the one in the Run arguments. This means that developers who refactored a class will instantly see +this failing in the simulator before sending the build and would realize they did something wrong. + +We will also fail if `start()` or one of the other methods in the main class declares a `throws` clause. This happens +a lot of times because new developers use IDE auto-correct suggestions and add a such a clause automatically. +Hopefully existing/working applications won’t be impacted by this…​ + +### Faster Margin/Padding + +Up until recently the official way to get the padding/margin of a component was something like this: + + + int paddingLeft = style.getPadding(cmp.isRTL(), Component.LEFT); + +That seems simple enough but there are a lot of hidden problems here. Normally this wouldn’t be a big deal but +both padding and margin are used in performance critical paths for rendering which impacts performance directly. + +__ | Performance critical paths are places in the code that can be invoked 60 times per second e.g. in the +painting logic, they must be **really** fast +---|--- + +The get padding method is implemented like this: + + + public int getPadding(boolean rtl, int orientation) { + int v = getPaddingValue(rtl, orientation); + return convertUnit(paddingUnit, v, orientation); + } + public int getPaddingValue(boolean rtl, int orientation) { + if (orientation < Component.TOP || orientation > Component.RIGHT) { + throw new IllegalArgumentException("wrong orientation " + orientation); + } + + if (rtl) { + switch(orientation) { + case Component.LEFT: + orientation = Component.RIGHT; + break; + case Component.RIGHT: + orientation = Component.LEFT; + break; + } + } + + return padding[orientation]; + } + +I’ll skip the `convertUnit` call since that’s pretty much fixed but as you can see there are several problems: + + 1. We will always have an `if` on RTL even if we don’t need it. We don’t always need it e.g. in the case for +top/bottom or a case where we need both left & right + + 2. We need to check that the orientation is valid + + 3. We have a redundant method call to the value method + + 4. All of these get compounded for cases where we need 2 orientations at once + +To solve these issues we replaced thru out the entire code all usage of these methods with these: + + + public int getPaddingLeft(boolean rtl); + public int getPaddingRight(boolean rtl); + public int getPaddingTop(); + public int getPaddingBottom(); + public int getPaddingLeftNoRTL(); + public int getPaddingRightNoRTL(); + public int getHorizontalPadding(); + public int getVerticalPadding(); + +We did the same for margin which I’m not listing here as it is practically identical. As you can see from the implementation +of `getPaddingLeft` it is **much** faster/smaller than **getPadding** : + + + public int getPaddingLeft(boolean rtl) { + if (rtl) { + return convertUnit(paddingUnit, padding[Component.RIGHT], Component.RIGHT); + } + return convertUnit(paddingUnit, padding[Component.LEFT], Component.LEFT); + } + +The other methods provide similar optimizations that should align across the board. + +The performance difference probably won’t be noticeable for most use cases. However I still think there is value +in understanding this. If you understand this change you can look for similar problematic usages in your code +and also within ours. When a method is deep enough within the call stack it becomes invisible to profilers and +we no longer see it. It’s important to challenge that and inspect the low level implementations especially if they have +been in the code for years. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Linsong Wang** — December 1, 2016 at 5:57 pm ([permalink](https://www.codenameone.com/blog/fail-fast-margin-padding-performance.html#comment-22836)) + +> Linsong Wang says: +> +> One request for this [codenameone_settings.proper…]() file: please do not automatically update the timestamp in the comment lines at the top of file, or remove comments completely. And, please keep a defined order of these properties. +> The constant change of this file (even there is no real content change) causes headache when team members work together with one git repo. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffail-fast-margin-padding-performance.html) + + +### **Shai Almog** — December 2, 2016 at 5:30 am ([permalink](https://www.codenameone.com/blog/fail-fast-margin-padding-performance.html#comment-23007)) + +> Shai Almog says: +> +> That’s a great idea, it was annoying to me too but I didn’t think of a solution until you asked… The problem is that we use java.util.Properties which uses Hashtable and is effectively broken in that sense. I can probably adapt this [http://stackoverflow.com/qu…]() to use globally and keep a consistent order. +> We’ll still need to update the libVersion but it would make merging easier. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffail-fast-margin-padding-performance.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/fast-push-communication-using-pubnub.md b/docs/website/content/blog/fast-push-communication-using-pubnub.md new file mode 100644 index 0000000000..d954ac34ee --- /dev/null +++ b/docs/website/content/blog/fast-push-communication-using-pubnub.md @@ -0,0 +1,150 @@ +--- +title: Fast Push Communication Using PubNub +slug: fast-push-communication-using-pubnub +url: /blog/fast-push-communication-using-pubnub/ +original_url: https://www.codenameone.com/blog/fast-push-communication-using-pubnub.html +aliases: +- /blog/fast-push-communication-using-pubnub.html +date: '2013-11-23' +author: Shai Almog +--- + +![Header Image](/blog/fast-push-communication-using-pubnub/fast-push-communication-using-pubnub-1.jpg) + + + + + +![Picture](/blog/fast-push-communication-using-pubnub/fast-push-communication-using-pubnub-1.jpg) + + + + +This came out 5 months ago but the guy from +[ +PubNub +](http://www.pubnub.com) +didn’t update us on the status so we just didn’t notice this until now. That’s probably a good sign of us being too busy. There is now official PubNub integration for Codename One, which means you can get push like fast 2 way communications between devices without writing too much code. + + +How does it work? + + + +PubNub has CDN like operations around the world, this means they can keep a high performance channel to your devices and send peer to peer or server/peer messages REALLY fast. + + +How is this different from just using Push notification? + + + +These aren’t separate ideas, push is generally good if the application isn’t running. Its also good for very small messages and provides no delivery guarantees. So using push for a chat application might not be the right thing but using PubNub for that makes perfect sense. + + +There is now a +[ +Codename One SDK from PubNub +](http://www.pubnub.com/docs/java/codenameone/codenameone-sdk.html) +and +[ +a tutorial +](http://www.pubnub.com/docs/java/codenameone/tutorial/data-push.html) + +related to the SDK that should help you get started right away and even a +[ +quick start tutorial +](http://www.pubnub.com/docs/java/codenameone/tutorial/quick-start.html) +. Normally we write a tutorial for things such as these but the guys at PubNub did such a good job at making this really simple, there is really no need to do so. Check out their work and let us know what you think. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — April 22, 2014 at 9:28 am ([permalink](https://www.codenameone.com/blog/fast-push-communication-using-pubnub.html#comment-22003)) + +> Anonymous says: +> +> Just spent a day looking at this finally, its kind of tough to get started for the first couple of hours but after that its plain sailing, made a whatsapp clone in 7 hrs that runs on all mobiles, thanks to codenameone 😀 Im amazed pubnub have put together such a decent and problem free API and extremely bloody thankful. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffast-push-communication-using-pubnub.html) + + +### **Anonymous** — September 6, 2014 at 8:07 pm ([permalink](https://www.codenameone.com/blog/fast-push-communication-using-pubnub.html#comment-24239)) + +> Anonymous says: +> +> Please someone help me out,I don’t know where to start in pubnub +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffast-push-communication-using-pubnub.html) + + +### **Anonymous** — September 7, 2014 at 3:00 am ([permalink](https://www.codenameone.com/blog/fast-push-communication-using-pubnub.html#comment-21878)) + +> Anonymous says: +> +> Did you go thru the tutorial on their website? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffast-push-communication-using-pubnub.html) + + +### **Anonymous** — September 7, 2014 at 8:31 am ([permalink](https://www.codenameone.com/blog/fast-push-communication-using-pubnub.html#comment-21733)) + +> Anonymous says: +> +> I did but not understanding anything there. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffast-push-communication-using-pubnub.html) + + +### **Anonymous** — September 7, 2014 at 1:31 pm ([permalink](https://www.codenameone.com/blog/fast-push-communication-using-pubnub.html#comment-22040)) + +> Anonymous says: +> +> This [http://www.pubnub.com/docs/…]() seems really simple. Do you have any Java programming experience? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffast-push-communication-using-pubnub.html) + + +### **Anonymous** — September 18, 2014 at 5:09 am ([permalink](https://www.codenameone.com/blog/fast-push-communication-using-pubnub.html#comment-22198)) + +> Anonymous says: +> +> Helo Gareth,am jude.Am trying to create a mobile chat application for my project.I want to create something similar to whatsap and skype for android,but am not sure how to go about this.Please can you give me tips on how to do this project.Thanks in advance +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffast-push-communication-using-pubnub.html) + + +### **Linsong Wang** — December 19, 2016 at 8:08 pm ([permalink](https://www.codenameone.com/blog/fast-push-communication-using-pubnub.html#comment-23161)) + +> Linsong Wang says: +> +> Pubnub is deprecating 3.x version, and 4.x is the recommended now. Any plan to upgrade corresponding cn1lib? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffast-push-communication-using-pubnub.html) + + +### **Shai Almog** — December 20, 2016 at 5:28 am ([permalink](https://www.codenameone.com/blog/fast-push-communication-using-pubnub.html#comment-23277)) + +> Shai Almog says: +> +> We didn’t build that cn1lib. It was built by pubnub. I think there are no technical issues in porting it to the new API as Codename One supports sockets/websockets and allows any form of communication including native interfaces. +> +> However, I don’t think they see enough paying user engagement from Codename One so if you rely on their service you need to write to them and ask for this. +> +> On our side we’d like to offer a better webservice oriented tool that will work with websockets for efficient universal communications. There is no current ETA for this though as this is still on the drawing board. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffast-push-communication-using-pubnub.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/faster-builds-performance.md b/docs/website/content/blog/faster-builds-performance.md new file mode 100644 index 0000000000..6e43591349 --- /dev/null +++ b/docs/website/content/blog/faster-builds-performance.md @@ -0,0 +1,77 @@ +--- +title: Faster Builds & Performance +slug: faster-builds-performance +url: /blog/faster-builds-performance/ +original_url: https://www.codenameone.com/blog/faster-builds-performance.html +aliases: +- /blog/faster-builds-performance.html +date: '2014-08-05' +author: Shai Almog +--- + +![Header Image](/blog/faster-builds-performance/faster-builds-performance-1.png) + + + + + +![Picture](/blog/faster-builds-performance/faster-builds-performance-1.png) + + + + +Despite quite a few regressions with the new VM we were finally able to make some major improvements to its performance and bring it on-par with native. Its still not as fast as it could be but coupled with the far improved GC and far superior synchronization its probably a better choice in terms of performance than the old VM. We are still heavily improving it to make it even better. + + +On that note, one of the major goals of this VM was in reducing build times. This took a turn to the worse this week with builds in excess of 16 minutes which effectively ground our servers to a halt. Turns out that the LLVM compiler used by Apple is pretty fast for most state of the art C/Objective-C but is downright awful for a simple #define statement. We used a lot of macros to simplify some of the generated code, but apparently the compiler chocked on them so badly it just took up all the CPU. + + + + +This was remarkably hard to track down since we have hundreds of thousands of lines of generated code in a typical application and benchmarking the compiler is pretty much a process of trial and error. + + + + +The servers are now up to date with a faster VM and we are also bringing in additional servers to handle the excess load and reduce the time spent in queued mode during build. This should make build times noticeably shorter regardless of whether you use the new VM or not. + + + + + + +Notice that we are now rolling out our first Mac servers based on Mavericks (new Mac OS version) which broke some things in our build scripts. We made some fixes but this might trigger some regressions in the next few days as we adjust our scripts. + + + + +On the code side of things Chen made some improvements to the image viewer and Tabs component which include improved animations and additional image sizing options. + + + + + + + + + + + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/faster-ios-builds-gui-builder-improvements-sql-updates.md b/docs/website/content/blog/faster-ios-builds-gui-builder-improvements-sql-updates.md new file mode 100644 index 0000000000..e65a1e2758 --- /dev/null +++ b/docs/website/content/blog/faster-ios-builds-gui-builder-improvements-sql-updates.md @@ -0,0 +1,109 @@ +--- +title: Faster iOS Builds, GUI Builder Improvements & SQL Updates +slug: faster-ios-builds-gui-builder-improvements-sql-updates +url: /blog/faster-ios-builds-gui-builder-improvements-sql-updates/ +original_url: https://www.codenameone.com/blog/faster-ios-builds-gui-builder-improvements-sql-updates.html +aliases: +- /blog/faster-ios-builds-gui-builder-improvements-sql-updates.html +date: '2016-10-24' +author: Shai Almog +--- + +![Header Image](/blog/faster-ios-builds-gui-builder-improvements-sql-updates/generic-java-2.jpg) + +I’ve recently noticed that distribution build sizes were identical for appstore and debug builds which wasn’t the case +before the xcode 7.x migration we did a while back. This shouldn’t be the case as it indicates that the standard +debug builds include both the 64bit and 32bit code which is redundant during debugging. + +We made some changes that should apply for the next update this Friday that might double build speed for some of +you as it will do less work during compiling but also produce a smaller binary. + +__ | I would also recommend unchecking “include source” which slows down the build as the zip and upload of +a huge file slows down the whole process +---|--- + +### GUI Builder Update + +I wanted to put out a new demo today and I have something really nice on the way…​ But then we decided to do it +with the GUI builder which resulted in about [15 issues so far](https://github.com/codenameone/CodenameOne/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20guibuilder). + +So the good news is that we are improving the GUI builder and tracking down bugs/inconveniences etc. The bad +news is that we’ll need to wait for a nice new demo for next week as this is pretty difficult. + +We also added quite a few cool new features to the GUI builder such as: + + * Ability to refresh to see the list of images added to the designer + + * Ability to add a new image directly from the GUI builder without launching the designer + + * UIID editing that allows us to pick from a list of UIID’s in the theme + +And quite a few other features. + +### SQL Updates + +Steve made some changes to the SQL Javadocs to clarify some SQL limitations in the JavaScript port. + +Besides the lack of portability for the SQL support there (due to the fact that SQL is not an official W3C standard), +there are two big issues: + + * Transactions can’t be mapped properly – the browser support for SQL wraps transactions in a very different way +and this can’t map to the Java side. + + * There is no database file so the trick of shipping a database file with your app and installing it won’t work! + +Ideally I’d love for us to have a better object persistence solution that will remove the need for SQL in the long +term. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Nick Koirala** — October 27, 2016 at 3:40 am ([permalink](https://www.codenameone.com/blog/faster-ios-builds-gui-builder-improvements-sql-updates.html#comment-22745)) + +> Nick Koirala says: +> +> What sort of solution are you thinking for an SQL replacement? The advantage of SQL in my mind compared to key/value storage is complex querying of the data. Its possible in NoSQL solutions of course, but they seem complicated to embed in platforms that (almost) all support SQLite. But a better solution is of course welcome, there are quirks and issues with SQLite – though I use it extensively as I don’t know of any good alternatives. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-builds-gui-builder-improvements-sql-updates.html) + + +### **Shai Almog** — October 28, 2016 at 3:43 am ([permalink](https://www.codenameone.com/blog/faster-ios-builds-gui-builder-improvements-sql-updates.html#comment-23143)) + +> Shai Almog says: +> +> We considered a lot of options but haven’t made a choice yet. While all platforms support a form of sqlite this is misleading as the functionality varies a lot resulting in device issues which is what we try to avoid. +> +> 1\. Offering hsql or a similar javadb as a cn1lib or even builtin – this will probably increase the dist size a bit so I’m a bit weary of it. I’m not too crazy about SQL either. +> 2\. Supporting one of the leading mobile object DB’s e.g. realm – While this has value this might be a problem as none of them is nearly as portable as we are e.g. the JavaScript port is always problematic. +> 3\. Build a simple Object storage maybe on top of something else – I’m hesitant to go into something like that. It’s not hard but those are famous last words… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-builds-gui-builder-improvements-sql-updates.html) + + +### **Nick Koirala** — October 28, 2016 at 3:43 am ([permalink](https://www.codenameone.com/blog/faster-ios-builds-gui-builder-improvements-sql-updates.html#comment-23094)) + +> Nick Koirala says: +> +> iOS 10.1 shows a message ‘This app may slow down your iPhone’ if its a 32bit build. *sigh* I guess it only affects debug / ad-hoc builds but it is a bit dumb. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-builds-gui-builder-improvements-sql-updates.html) + + +### **Akinniranye James** — November 1, 2016 at 3:51 pm ([permalink](https://www.codenameone.com/blog/faster-ios-builds-gui-builder-improvements-sql-updates.html#comment-23035)) + +> Akinniranye James says: +> +> Will vote for 1 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-builds-gui-builder-improvements-sql-updates.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/faster-ios-runtime-javazone-edition.md b/docs/website/content/blog/faster-ios-runtime-javazone-edition.md new file mode 100644 index 0000000000..d0d4de8598 --- /dev/null +++ b/docs/website/content/blog/faster-ios-runtime-javazone-edition.md @@ -0,0 +1,227 @@ +--- +title: Faster iOS Runtime – JavaZone Edition +slug: faster-ios-runtime-javazone-edition +url: /blog/faster-ios-runtime-javazone-edition/ +original_url: https://www.codenameone.com/blog/faster-ios-runtime-javazone-edition.html +aliases: +- /blog/faster-ios-runtime-javazone-edition.html +date: '2013-09-06' +author: Shai Almog +--- + +![Header Image](/blog/faster-ios-runtime-javazone-edition/faster-ios-runtime-javazone-edition-1.jpg) + + + + +[ +![Content of Shai's Backpack](/blog/faster-ios-runtime-javazone-edition/faster-ios-runtime-javazone-edition-1.jpg) +](/img/blog/old_posts/faster-ios-runtime-javazone-edition-large-2.jpg) + + + +Before we get into the subject of today’s post a small public service announcement: we recently added the ability to create annual pro subscriptions. This provides a 10% discount over our standard pro subscription rates. + + + + +I’m writing this while preparing for my JavaZone flight. What you see in the picture on the right is the typical content of my backpack which I carry with me everywhere in case there is a problem I need to debug, this is somewhat of a visual tutorial of “what it takes” to be a mobile developer today. I took this picture for the JavaZone presentation I’m making and I think it illustrates well why Codename One exists (BTW it is missing some of my testing devices such as the iPad 2, the Android tablets and a few J2ME phones). From left to right top to bottom: + + 1. +Windows 8 Machine (for building Windows Phone apps) + + 2. +iPad 3 (retina – iOS 7 beta) + + 3. +Mac (for building iOS apps) + + 4. +Blackberry Z10 (BB OS 10) + + + 5. +Nokia Asha (S40) + + 6. +iPod Touch (iOS 6) + + 7. +Nexus One (Gingerbread) + + 8. +Galaxy Nexus (Jelly Bean) + + 9. +Blackberry Torch (BB OS 6) + + 10. +Nokia Lumia 520 (Windows Phone 8) + + + + +Who said mobile development isn’t back breaking work! + + + + + +And now for something completely different: On iOS the translation tool we use for converting bytecode to xcode applications is tuned for compatibility more than it is tuned for speed. This means that generated code performs a lot of null pointer checks (so it can throw a NullPointerException) and performs array boundary checks. Both of these effectively slow the execution of your application significantly. + + +We now have a new build flag for iOS called: + +ios.unsafe + + +If you define that build argument as true: + +ios.unsafe=true + + +You will get an application that won’t throw ArrayIndexOutOfBounds exceptions or NullPointerExceptions, however it might crash for such cases! + + + +This is one of those flags that you will need to test REALLY well before using in production, however once enabled it should drastically improve the performance of Codename One. + + +Notice that some things are never tested by the translated code such as class cast exception etc. (so code that relies on those will just crash). + + +We are now in the process of re-designing our iOS backend which includes some tough decisions regarding backend technology, our goals are: + + + 1. +Shortening build times. + + + + 2. +Improved crash analysis + + +. + + + + + 3. +Faster execution. + + + + + 4. +Improved graphics support. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — September 9, 2013 at 8:55 am ([permalink](https://www.codenameone.com/blog/faster-ios-runtime-javazone-edition.html#comment-21957)) + +> Anonymous says: +> +> how much weight this total stuff 😉 ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-runtime-javazone-edition.html) + + +### **Anonymous** — September 20, 2013 at 8:33 am ([permalink](https://www.codenameone.com/blog/faster-ios-runtime-javazone-edition.html#comment-22023)) + +> Anonymous says: +> +> If we don’t use the ‘unsafe’ flag, do unnecessary null pointer checks get optimised out anyway? +> +> If the Java->C conversion just converts the opcodes, you’ll get a lot of unnecessary ones. e.g. References to ‘this’ will still have the check, as will references returned from the ‘new’ operator. I think you can also cut out quite a lot by only checking references stored in local variables once after each assignment. +> +> I think you can make considerable speed savings with those techniques, and they aren’t that hard to implement. Importantly, you don’t change the semantics of the code at all… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-runtime-javazone-edition.html) + + +### **Anonymous** — September 20, 2013 at 2:17 pm ([permalink](https://www.codenameone.com/blog/faster-ios-runtime-javazone-edition.html#comment-21930)) + +> Anonymous says: +> +> Back breaking weight… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-runtime-javazone-edition.html) + + +### **Anonymous** — September 20, 2013 at 2:18 pm ([permalink](https://www.codenameone.com/blog/faster-ios-runtime-javazone-edition.html#comment-21628)) + +> Anonymous says: +> +> True, the main cost though is in loops. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-runtime-javazone-edition.html) + + +### **Anonymous** — September 23, 2013 at 5:50 am ([permalink](https://www.codenameone.com/blog/faster-ios-runtime-javazone-edition.html#comment-21980)) + +> Anonymous says: +> +> Yes, there are a few things you can do to speed loops up, though mostly only when you’re using final/local variables due to potential threading issues. +> +> Anyway, my question was: do you do any of those optimisations when ios.unsafe = false? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-runtime-javazone-edition.html) + + +### **Anonymous** — September 23, 2013 at 8:56 am ([permalink](https://www.codenameone.com/blog/faster-ios-runtime-javazone-edition.html#comment-21965)) + +> Anonymous says: +> +> No. The only thing the unsafe flag does is remove the checks, most of the optimizations in the LLVM compiler from Apple are actually pretty great although we can/should definitely improve threading/monitors. +> +> I’m now in the process of overhauling our entire VM/graphics infrastructure so I’m looking into improvements there as well. +> +> (Replying to myself since blog software supports limited nesting) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-runtime-javazone-edition.html) + + +### **Anonymous** — January 10, 2014 at 12:07 am ([permalink](https://www.codenameone.com/blog/faster-ios-runtime-javazone-edition.html#comment-21959)) + +> Anonymous says: +> +> So what happens when things crash with this flag set? App just vanishes with no message? Im going to turn it on right now!!! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-runtime-javazone-edition.html) + + +### **Anonymous** — January 10, 2014 at 12:12 am ([permalink](https://www.codenameone.com/blog/faster-ios-runtime-javazone-edition.html#comment-21882)) + +> Anonymous says: +> +> ps – does this mean it will run faster than Android? or not ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-runtime-javazone-edition.html) + + +### **Anonymous** — January 10, 2014 at 2:50 am ([permalink](https://www.codenameone.com/blog/faster-ios-runtime-javazone-edition.html#comment-22056)) + +> Anonymous says: +> +> It will crash. You can disable exception messages without using this by defining an error handler. +> +> Android has a JIT, static compilation can’t beat JIT for some use cases. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffaster-ios-runtime-javazone-edition.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/featured-app-ana-paltel.md b/docs/website/content/blog/featured-app-ana-paltel.md new file mode 100644 index 0000000000..ea966de1fe --- /dev/null +++ b/docs/website/content/blog/featured-app-ana-paltel.md @@ -0,0 +1,38 @@ +--- +title: Featured App – Ana Paltel +slug: featured-app-ana-paltel +url: /blog/featured-app-ana-paltel/ +original_url: https://www.codenameone.com/blog/featured-app-ana-paltel.html +aliases: +- /blog/featured-app-ana-paltel.html +date: '2016-07-20' +author: Shai Almog +--- + +![Header Image](/blog/featured-app-ana-paltel/ana-paltel.jpg) + +Millions of Codename One apps are installed on devices every month. Most of them aren’t in the gallery +and are never featured in this recurring segment. We are looking for something exceptional in apps that +we feature here and [Ana Paltel](/featured-ana-paltel.html) fits that bill. It has a polished UI and it’s +shipped by a major operator. It uses some unique Codename One features to boot making it even more interesting. + +We liked the usage of the native Google Maps integration that provides +information about service points and directions. The UI as you can see from the screenshots above is +rich, it provides gauge charts and other visual niceties that are builtin directly into Codename One. + +Since the app is localized in Arabic and English it makes use of Codename One’s native bidi/RTL support +which is essential for middle eastern languages. It also makes use of push notification and a few other +device capabilities. + +The app is shipping both on [iOS](https://itunes.apple.com/dm/app/ana-paltel/id1131291631) & on +[Android](https://play.google.com/store/apps/details?id=com.paltel.mobapp) and as of this time +it’s open to users in other regions so I was able to install it and take it to a spin. Even thought I couldn’t +physically login there is a lot of functionality that’s exposed on the guest account. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/featured-app-jat-communication.md b/docs/website/content/blog/featured-app-jat-communication.md new file mode 100644 index 0000000000..2ef7e360dc --- /dev/null +++ b/docs/website/content/blog/featured-app-jat-communication.md @@ -0,0 +1,73 @@ +--- +title: Featured App – JAT Communication +slug: featured-app-jat-communication +url: /blog/featured-app-jat-communication/ +original_url: https://www.codenameone.com/blog/featured-app-jat-communication.html +aliases: +- /blog/featured-app-jat-communication.html +date: '2016-04-23' +author: Shai Almog +--- + +![Header Image](/blog/featured-app-jat-communication/jat.png) + +The jat app is very similar to whatsapp in some regards but is more oriented towards group communication +than SMS replacement. Over the past couple of weeks we picked it up as a great communication tool in our team. +It uses push notifications to notify and activates accounts via SMS. This makes it very convenient for someone +like myself who moves between devices constantly. + +Chat is a very common use case for developers in the Codename One community which is why I chose this app +as one of our first highlighted apps. I highly recommend playing with the app to see some of the things you +can do in Codename One. + +You can see the app [featured page here](/featured-jat.html). You can check out the +[ios version here](https://itunes.apple.com/il/app/jat-communication/id1094392187) and the +[android version here](https://play.google.com/store/apps/details?id=com.jat.app). + +Side menu + +[![Side Menu](/blog/featured-app-jat-communication/featured-jat-1.png)](/img/featured/featured-jat-1.png) + +Activities + +[![Activities](/blog/featured-app-jat-communication/featured-jat-3.png)](/img/featured/featured-jat-3.png) + +__ | If you want to add your app to the featured app list just let us know here or in the discussion forum +---|--- +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Stefan Eder** — April 25, 2016 at 7:17 am ([permalink](https://www.codenameone.com/blog/featured-app-jat-communication.html#comment-22621)) + +> Apparently the app is only available in the israel app store +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffeatured-app-jat-communication.html) + + +### **Shai Almog** — April 26, 2016 at 4:15 am ([permalink](https://www.codenameone.com/blog/featured-app-jat-communication.html#comment-22485)) + +> Thanks for the headsup. I didn’t notice this when I posted this, it seems they are still in tiered beta. +> I’ll try to update when this becomes available globally. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffeatured-app-jat-communication.html) + + +### **Fabrizio Grassi** — June 15, 2016 at 4:45 pm ([permalink](https://www.codenameone.com/blog/featured-app-jat-communication.html#comment-21513)) + +> Fabrizio Grassi says: +> +> Hi, I would like iJobClock to be in the a featured app list, is it possible? what should I do? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffeatured-app-jat-communication.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/featured-app-pumpop.md b/docs/website/content/blog/featured-app-pumpop.md new file mode 100644 index 0000000000..4644696cfd --- /dev/null +++ b/docs/website/content/blog/featured-app-pumpop.md @@ -0,0 +1,90 @@ +--- +title: Featured App – Pumpop +slug: featured-app-pumpop +url: /blog/featured-app-pumpop/ +original_url: https://www.codenameone.com/blog/featured-app-pumpop.html +aliases: +- /blog/featured-app-pumpop.html +date: '2016-05-10' +author: Shai Almog +--- + +![Header Image](/blog/featured-app-pumpop/pumpop-landscape.png) + +Pumpop is a social networking app in the spirit of tinder that is available globally and installed on many devices +all over the world. One of its major draws is it’s portability which will soon extend to Windows Phone as well. + +Pumpop uses social login controls such as native Facebook login as well as email activation. + +__ | If you are in a committed relationship I suggest notifying your spouse that you are “just testing this app for work”, +to avoid unpleasantness and suspicion…​ +---|--- + +You can see the app [featured page here](/featured-pumpop.html). You can check out the +[ios version here](https://itunes.apple.com/us/app/pumpop-date-chat-and-friends/id694132364) and the +[android version here](https://play.google.com/store/apps/details?id=com.pumpop.pumpop). + +Chats list + +[![Chats list](/blog/featured-app-pumpop/featured-pumpop-1.png)](/img/featured/featured-pumpop-1.png) + +Nearby + +[![Nearby](/blog/featured-app-pumpop/featured-pumpop-2.png)](/img/featured/featured-pumpop-2.png) + +Like Profile + +[![Like Profile](/blog/featured-app-pumpop/featured-pumpop-3.png)](/img/featured/featured-pumpop-3.png) + +Profile Details + +[![Profile Details](/blog/featured-app-pumpop/featured-pumpop-4.png)](/img/featured/featured-pumpop-4.png) + +### Contributions + +One of the things that should be mentioned about the guys from Pumpop is that they “walk the walk”. +Fabricio of [pmovil](http://www.pmovil.com) (the company behind Pumpop) has contributed a great deal of code +to the Codename One community most of which is shown in their [github profile](https://github.com/Pmovil/). + +Fabricio contributed multiple cn1libs ranging in functionality from [native Toast support](https://github.com/Pmovil/Toast) +to [comscore analytics](https://github.com/Pmovil/comScore). But his biggest work has been his +[custom Windows Phone/UWP port](https://github.com/Pmovil/CN1WindowsPort) which served as a basis +for our newer port! + +That is gumption in it’s true hacker sense and truly represents the open source spirit we try to foster within +Codename One. If he hadn’t done all of that work we might not have even started with the UWP port effort +so if you are looking forward to the new Windows support you have Fabricio and Pmovil to thank for that. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Ross Taylor** — May 12, 2016 at 2:56 pm ([permalink](https://www.codenameone.com/blog/featured-app-pumpop.html#comment-22891)) + +> Interesting app. However I noticed an annoying bug though, for example when switching between other apps using the overview button (task switcher) while the chat form is showing, going back to this app again, the message input bar disappears only leaving the typed text visible (tested on android 4.3.1). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffeatured-app-pumpop.html) + + +### **Fabrício Cabeça** — May 13, 2016 at 1:14 pm ([permalink](https://www.codenameone.com/blog/featured-app-pumpop.html#comment-22695)) + +> Thanks Ross for the feedback ! I didn’t find it that annoying but it was marked as a bug to be fixed in the next version. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffeatured-app-pumpop.html) + + +### **Ross Taylor** — May 17, 2016 at 10:17 am ([permalink](https://www.codenameone.com/blog/featured-app-pumpop.html#comment-22574)) + +> Hi Fabricio, thats great! Also would it be possible to add in paragraph support for typing in the text conversations? That would be nice :). Another lookout point is whether if its possible to make the UI more native looking to the OS (eg material design for Android etc) by sticking to their guidelines, while still preserving the fun. I also noticed a slight flickering in the background when menu actions are accessed and the action list box sometimes get stuck at the bottom when the keyboard is minimized and the screen maximized. Good luck! Looking forward to the next update..Ross. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffeatured-app-pumpop.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/featured-app-yhomework.md b/docs/website/content/blog/featured-app-yhomework.md new file mode 100644 index 0000000000..a25b89c3ef --- /dev/null +++ b/docs/website/content/blog/featured-app-yhomework.md @@ -0,0 +1,106 @@ +--- +title: Featured App – yHomework +slug: featured-app-yhomework +url: /blog/featured-app-yhomework/ +original_url: https://www.codenameone.com/blog/featured-app-yhomework.html +aliases: +- /blog/featured-app-yhomework.html +date: '2016-05-18' +author: Shai Almog +--- + +![Header Image](/blog/featured-app-yhomework/yhomework.jpg) + +We’re all pretty jaded when it comes to software but when I first saw yHomework I was completely floored by it! + +Where was this tool when I was in junior high? + +If you haven’t seen [yHomework](http://www.yhomework.com/) in action I suggest you give it a try right now on your +[Android](https://play.google.com/store/apps/details?id=com.MathUnderground.MathSolver) or +[iOS device](https://itunes.apple.com/us/app/yhomework/id604715759). + +In a nutshell the app accepts several types of math equations starting with the basic algebra e.g `3(x+5)=6` and then +shows you the process of solving it as if a human teacher solved it for you. Including text explanation of every step +that you can just read thru and understand! + +This is ideal for students picking up the higher level math subjects who might struggle with an exercise, why does +the answer in the book differ from my result? + +### In Codename One + +[yHomework](http://www.yhomework.com/) was one of the first major Codename One apps ever written, some of +our features were explicitly built to help this app. Originally the author wrote an entire implementation in JavaScript +and scrapped the whole thing our of concern for IP issues & a personal preference for Java. + +__ | Despite obfuscation JavaScript apps (e.g. PhoneGap/Cordova) can be unzipped and resold which is a +common practice in some markets +---|--- + +The app makes use of many Codename One features including in-app-purchase, cn1libs for the ads, push notification etc. + +In fact the app was so successful that it brought down our old push notification servers back in the day. + +#### Portability + +yHomework benefited greatly from it’s portability as a few years ago a competing iOS app went on a media blitz. +yHomework saw it’s marketshare rise both on iOS and Android thanks to that competitors campaign. The rise +was especially pronounced on Android (where the competitor wasn’t present) but also carried into iOS thanks +to the social sharing effect. + +With installs in the millions and great reviews yHomework shows that cross platform can be a fan favorite +where the complaints users have are more around the fact that the app isn’t completely free than anything else…​ + +If I had to pick a favorite Codename One app I would pick yHomework. It shows that content and functionality +is still king & the most important thing an app can deliver. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — May 19, 2016 at 3:48 pm ([permalink](https://www.codenameone.com/blog/featured-app-yhomework.html#comment-22602)) + +> Chidiebere Okwudire says: +> +> I remember downloading the app over a year ago and the graphics on my phone were pretty poor… Maybe I’ll check it out again. +> +> By the way, how do you make the app showcase images like the one at the top of this post? I’m looking for a tool to be able to do similar stuff. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffeatured-app-yhomework.html) + + +### **bryan** — May 19, 2016 at 11:46 pm ([permalink](https://www.codenameone.com/blog/featured-app-yhomework.html#comment-22553)) + +> bryan says: +> +> That’s a very slick looking app. Any idea what sort of time it took to develop ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffeatured-app-yhomework.html) + + +### **Shai Almog** — May 20, 2016 at 4:15 am ([permalink](https://www.codenameone.com/blog/featured-app-yhomework.html#comment-22910)) + +> Shai Almog says: +> +> The UI was designed before flat design took over, the general design was around the idea of familiarity to 7th-10th grade kids (notebook, calculator motif). My one complaint about the UI is it’s performance which I think could be improved significantly. +> Since this app is so old by now it was developed before there were “best practices” for Codename One and a lot of things could probably be accomplished in a more efficient way. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffeatured-app-yhomework.html) + + +### **Shai Almog** — May 20, 2016 at 4:16 am ([permalink](https://www.codenameone.com/blog/featured-app-yhomework.html#comment-22542)) + +> Shai Almog says: +> +> The core UI was written in a few months but overall this app has been in production since 2013 or so. The current level of functionality and UI evolved over time. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffeatured-app-yhomework.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/file-chooser-xcode-10.md b/docs/website/content/blog/file-chooser-xcode-10.md new file mode 100644 index 0000000000..d566386448 --- /dev/null +++ b/docs/website/content/blog/file-chooser-xcode-10.md @@ -0,0 +1,97 @@ +--- +title: File Chooser on Xcode 10.1 +slug: file-chooser-xcode-10 +url: /blog/file-chooser-xcode-10/ +original_url: https://www.codenameone.com/blog/file-chooser-xcode-10.html +aliases: +- /blog/file-chooser-xcode-10.html +date: '2019-02-11' +author: Shai Almog +--- + +![Header Image](/blog/file-chooser-xcode-10/xcode-migration.jpg) + +The recent migration to [xcode 10.1](/blog/xcode-10-1-migration-phase-2.html) broke builds for apps using the [file chooser](/blog/native-file-open-dialogs.html) API. In order to use that API we need to make changes to the provisioning profile to include iCloud support. With the new version you must have a container associated with iCloud for this to work. + +To fix this follow these steps: + + * Login to + + * Under App IDs select your app + + * Click Edit + + * Check iCloud and select Include CloudKit support (requires Xcode 6) + +![iCloud Settings](/blog/file-chooser-xcode-10/icloud-settings.png) + +Figure 1. iCloud Settings + + * Create a new iCloud container and give it a unique name/package + + * Go back to the icloud settings edit mode and select the new container in the list of containers as such + +![Select the Container](/blog/file-chooser-xcode-10/icloud-container.png) + +Figure 2. Select the Container + + * Next regenerate and download the provisioning profiles, replace the ones in your app with the new provisioning profiles + +Notice that this will only work with the default xcode 10.1 mode. It seems that the application loader now requires this as Apple no longer accepts binaries with xcode 9.2 that use the older approach (without containers). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Eric Kimotho** — January 15, 2021 at 3:51 pm ([permalink](https://www.codenameone.com/blog/file-chooser-xcode-10.html#comment-24378)) + +> Thank you for this. Apple website was updated and menus rearranged. Below are the steps I followed. +> 1 Login to developer account +> +> 2 Select Certificates, Identifiers & Profiles +> +> 3 Select iCloud containers from drop down in the right (where default value shown is App IDs) +> +> 4 Click + icon to add new identifier/container – by default iCloud containers will be selected +> +> 5 Click Continue +> +> 6 Enter description eg Name of the CN1 app, +> +> 7 Enter identifier eg CN1 app package name and click continue, note iCloud prefix will be added by default +> +> 8 Click Register +> +> 9 You are taken back to identifiers listing created iCloud containers +> +> 10 Select App IDs from drop down in the right +> +> 11 Select app you need to enable iCloud (Note Apps are appearing here after sending successful iOS build, note in this case filechooser lib should first be uninstalled from project (using this link ) for build to be successful) +> +> 12 Scroll down and check iCloud then select include CloudKit support (requires Xcode 6) +> +> 13 Click Edit button, a dialog with iCloud containers will show +> +> 14 Select iCloud container to use and click continue +> +> 15 Click save button at top right corner +> +> 16 A warning dialog that provisioning will be revalidated and need to be regenerated will show, click continue +> +> 17 Back to IDE reinstall filechooser lib +> +> 18 Under project’s iosCerts folder, delete both provisioning profiles and rerun certificate wizard to regenerate provisioning profiles which will now have iCloud enabled +> +> 19 Send iOS build, should be successful now +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffile-chooser-xcode-10.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/file-url-java-mobile-compatibility.md b/docs/website/content/blog/file-url-java-mobile-compatibility.md new file mode 100644 index 0000000000..0e4d981227 --- /dev/null +++ b/docs/website/content/blog/file-url-java-mobile-compatibility.md @@ -0,0 +1,41 @@ +--- +title: File and URL for Better Java Mobile Compatibility +slug: file-url-java-mobile-compatibility +url: /blog/file-url-java-mobile-compatibility/ +original_url: https://www.codenameone.com/blog/file-url-java-mobile-compatibility.html +aliases: +- /blog/file-url-java-mobile-compatibility.html +date: '2016-10-19' +author: Shai Almog +--- + +![Header Image](/blog/file-url-java-mobile-compatibility/port-java-code.jpg) + +I explained [why we don’t support the full Java API](/blog/why-we-dont-support-the-full-java-api.html) +(and the difficulties involved) not so long ago. The logic behind this is solid. However, the utility of porting +existing Java code to Codename One is also with a lot of merit. + +We try to strike a balance between portability, compatibility to the Java API etc. and that is a very delicate +balance. To improve the situation we created two new classes: `com.codename1.io.File` & `com.codename1.io.URL`. +They are meant to be drop-in replacements for `java.io.File` & `java.net.URL` to help you port existing code. + +This doesn’t mean that every API will work or behave as you expect as the mapping is sometimes counter intuitive +e.g. `File` works with relative paths which we don’t support. We had some thoughts about the “right way” to +implement the `URL` API and eventually decided to use our internal synchronous API and not the high level +`ConnectionRequest` API. + +That means that the `URL` API can block the EDT (illegally) and should be used with caution. This makes it +more compatible with the JavaSE API of the same name. This also means that using URL should be completely +separate from `ConnectionRequest` and will not block the network thread when you do so. + +We’d like to start looking at big ticket Java libraries that people use that we can port to Codename One. So we +can learn from the process and provide both “best practices” and better support from within. +If you have a wishlist of a jars you want to use in Codename One let us know and we’ll add them to the consideration. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/fingerprint-touchid-support.md b/docs/website/content/blog/fingerprint-touchid-support.md new file mode 100644 index 0000000000..a996e580fa --- /dev/null +++ b/docs/website/content/blog/fingerprint-touchid-support.md @@ -0,0 +1,97 @@ +--- +title: Fingerprint/TouchID Support +slug: fingerprint-touchid-support +url: /blog/fingerprint-touchid-support/ +original_url: https://www.codenameone.com/blog/fingerprint-touchid-support.html +aliases: +- /blog/fingerprint-touchid-support.html +date: '2017-05-02' +author: Shai Almog +--- + +![Header Image](/blog/fingerprint-touchid-support/fingerprint-scanner.jpg) + +Fingerprint scanners are pretty common in modern hardware both from Apple and some Android vendors. The problem is that the iOS and Android API’s for accessing them are a world apart. However, it’s possible to find some low level common ground which is exactly what our [cn1lib for fingerprint scanning](https://github.com/codenameone/FingerprintScanner) accomplished. + +This is a very basic API that just validates the user as the owner of the device, it’s useful to lock off portions of the application from a 3rd party using code such as: + + + Fingerprint.scanFingerprint("Use your finger print to unlock AppName.", value -> { + Log.p("Scan successful!"); + }, (sender, err, errorCode, errorMessage) -> { + Log.p("Scan Failed!"); + }); + +Since the cn1lib is pretty simple it can probably be enhanced to support more elaborate functionality in the future. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Lukman Javalove Idealist Jaji** — May 4, 2017 at 5:43 am ([permalink](https://www.codenameone.com/blog/fingerprint-touchid-support.html#comment-24130)) + +> Lukman Javalove Idealist Jaji says: +> +> Fantastic. To think this is what I have been researching all week. But I do want something not too complex but maybe complex for cn1 at this time. I am ordering external finger print scanners to use with my apps (for data collection). The only way to achieve that I guess is to delve into native code. I will like to see this in the future, take advantage of the inbuilt fingerprint hardware on devices to collect fingerprint data and stored. More like +> +> if(Display.getInstance().isFPSupported()) +> { +> //Collect and store) +> } +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffingerprint-touchid-support.html) + + +### **Shai Almog** — May 5, 2017 at 4:46 am ([permalink](https://www.codenameone.com/blog/fingerprint-touchid-support.html#comment-23559)) + +> Shai Almog says: +> +> Great. I don’t think that’s allowed on iOS but you can probably extend the Android code in the library to support some Android specific features and expose them in the API. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffingerprint-touchid-support.html) + + +### **Gareth Murfin** — July 6, 2017 at 11:36 pm ([permalink](https://www.codenameone.com/blog/fingerprint-touchid-support.html#comment-24135)) + +> Gareth Murfin says: +> +> Awesome, but how does it know your finger print already? from the OS? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffingerprint-touchid-support.html) + + +### **Shai Almog** — July 7, 2017 at 4:17 am ([permalink](https://www.codenameone.com/blog/fingerprint-touchid-support.html#comment-22614)) + +> Shai Almog says: +> +> The devices already have scanned fingerprints within. You use the OS interface to scan. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffingerprint-touchid-support.html) + + +### **Yishai Steinhart** — July 6, 2018 at 7:37 pm ([permalink](https://www.codenameone.com/blog/fingerprint-touchid-support.html#comment-23791)) + +> Yishai Steinhart says: +> +> NM +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffingerprint-touchid-support.html) + + +### **Shai Almog** — July 7, 2018 at 4:50 am ([permalink](https://www.codenameone.com/blog/fingerprint-touchid-support.html#comment-23961)) + +> Shai Almog says: +> +> FYI to your original question I suggest installing the cn1lib via the extension manager as you would get the latest version… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffingerprint-touchid-support.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/first-class-eclipse-support.md b/docs/website/content/blog/first-class-eclipse-support.md new file mode 100644 index 0000000000..e4ad40357b --- /dev/null +++ b/docs/website/content/blog/first-class-eclipse-support.md @@ -0,0 +1,55 @@ +--- +title: First Class Eclipse Support +slug: first-class-eclipse-support +url: /blog/first-class-eclipse-support/ +original_url: https://www.codenameone.com/blog/first-class-eclipse-support.html +aliases: +- /blog/first-class-eclipse-support.html +date: '2017-01-09' +author: Shai Almog +--- + +![Header Image](/blog/first-class-eclipse-support/eclipse.jpg) + +Our eclipse IDE support has been around for quite a while now but has never stood up to the quality and update pace of NetBeans. Recently even our IntelliJ/IDEA support has surpassed the quality of our eclipse plugin and the blame should be on us. + +One of the problems is that our team doesn’t use eclipse and uses a diverse set of OS’s (Macs/Windows) which is problematic when sharing workspaces. Integrating the eclipse plugin build into our standard release process proved really hard and it ended up eventually as something we need to do but never got around to do it…​ + +We’ve spent the last couple of weeks trying to get eclipse to work with the release build process and it seems we got it right. Our latest version of the eclipse plugin was released with the other plugins and from now on we hope all the plugins will be released together! + +Please try updating the eclipse plugin, it should be 3.6.0 right now and would ideally be in sync with the versions from the other IDE’s. + +We integrated the new demos that are already a part of the newer IDE’s and we’ll try to better keep up with the changes from now on. The one major feature that is still missing from the eclipse plugin is support for cn1lib creation which we hope to add as we move forward. + +As part of this work I was very impressed by the improvements made in eclipse neon which is **much** better than previous iterations of eclipse (speaking as a Mac user). The IDE has been responsive and the UI has been closer to what one would expect in such a case. + +If you run into weird errors or regressions in the new eclipse plugin update please let us know ASAP. These might be related to the codebase transition and it’s important we get a handle on them quickly! + +__ | **Update:** It seems older versions of eclipse didn’t react well to the new plugin so with the new plugin we requite Neon and Java 8 +---|--- + +### New Updates to All Plugins + +We just released new updates to all the plugins for the 3.6 release. We are now in a week long code freeze and if there are no regressions there won’t be an update for the next two weeks. If we do find a regression we’ll push out a new 3.6 release candidate during the week and possibly postpone a weekly update after that. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **dingfelder** — January 12, 2018 at 8:37 am ([permalink](https://www.codenameone.com/blog/first-class-eclipse-support.html#comment-23679)) + +> dingfelder says: +> +> Hi – I’m using the eclipse version – a quick comment: the build process isn’t copying all the files the way I would expect – for instance, the sql demo requires a db file to be copied to the cn folder – currently this has to be done manually. I suspect this is hitting anyone trying to run the demos. cheers +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffirst-class-eclipse-support.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/first-uwp-app-and-the-way-forward.md b/docs/website/content/blog/first-uwp-app-and-the-way-forward.md new file mode 100644 index 0000000000..41bf16eb57 --- /dev/null +++ b/docs/website/content/blog/first-uwp-app-and-the-way-forward.md @@ -0,0 +1,127 @@ +--- +title: First UWP App and the Way Forward +slug: first-uwp-app-and-the-way-forward +url: /blog/first-uwp-app-and-the-way-forward/ +original_url: https://www.codenameone.com/blog/first-uwp-app-and-the-way-forward.html +aliases: +- /blog/first-uwp-app-and-the-way-forward.html +date: '2016-09-04' +author: Shai Almog +--- + +![Header Image](/blog/first-uwp-app-and-the-way-forward/solitaire-uwp.jpg) + +The UWP (Universal Windows Platform) port is finally stable enough to get an +[app into the Microsoft store](https://www.microsoft.com/en-us/store/p/codename-one-solitaire/9nblggh51z60). +Steve published out Solitaire demo into the Microsoft appstore and it passed thru the whole process. You +can download it, install it on your device and try it. + +We’ll try to setup a company account to publish the kitchen sink as well moving forward. + +This is a huge step for the UWP port showing its maturity and readiness for prime-time. + +### Future of Windows Phone Port + +We weren’t bullish on the continued maintenence of the Windows Phone port but with recent events e.g. MS discontinuing +Skype on Windows Phone it is pretty clear the platform is dead. Had the port been mature this wouldn’t have been a +problem, but the Windows Phone port has huge glaring problems…​ + +Fixing these problems is an enormous task and one that just isn’t viable for a discontinued platform. So we are officially +deprecating the Windows Phone target and will mark it as deprecated starting with the next release. + +At the moment we won’t remove it since we know people are still using it but we might do so in the near future as +we need to self host the servers to support this platform and that is a very problematic setup. These problems don’t +affect the UWP port! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — September 5, 2016 at 8:30 pm ([permalink](https://www.codenameone.com/blog/first-uwp-app-and-the-way-forward.html#comment-22735)) + +> bryan says: +> +> Overflow menu commands don’t display correctly +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffirst-uwp-app-and-the-way-forward.html) + + +### **Shai Almog** — September 6, 2016 at 3:56 am ([permalink](https://www.codenameone.com/blog/first-uwp-app-and-the-way-forward.html#comment-23006)) + +> Shai Almog says: +> +> Thanks, we noticed that too after this went live. It’s an odd issue. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffirst-uwp-app-and-the-way-forward.html) + + +### **bryan** — September 6, 2016 at 3:59 am ([permalink](https://www.codenameone.com/blog/first-uwp-app-and-the-way-forward.html#comment-22751)) + +> bryan says: +> +> It’s the same issue I raised a few days ago. It works fine in a debug build, but not in an app store build. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffirst-uwp-app-and-the-way-forward.html) + + +### **Ross Taylor** — September 6, 2016 at 12:51 pm ([permalink](https://www.codenameone.com/blog/first-uwp-app-and-the-way-forward.html#comment-22971)) + +> Ross Taylor says: +> +> Strange afaik, Skype will be discontinued for Windows phones 7 – 8.1, but nothing was mentioned about Windows Phone 10? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffirst-uwp-app-and-the-way-forward.html) + + +### **Shai Almog** — September 6, 2016 at 1:30 pm ([permalink](https://www.codenameone.com/blog/first-uwp-app-and-the-way-forward.html#comment-22946)) + +> Shai Almog says: +> +> MS’s lineup is a confusing mess. +> +> There is no Windows Phone 10 and there never will be. +> +> There is Windows 10 Mobile which is really a shrunk down version of Windows 10. To reach both Windows 10 (Desktop & Mobile) MS invented the Universal Windows Platform == UWP. +> +> So we support the Windows 10+ versions that run on phones, desktops and tablets. We are ending support for the exact same thing that Skype is no longer supporting. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffirst-uwp-app-and-the-way-forward.html) + + +### **Ross Taylor** — September 6, 2016 at 1:49 pm ([permalink](https://www.codenameone.com/blog/first-uwp-app-and-the-way-forward.html#comment-23021)) + +> Ross Taylor says: +> +> Ah, thanks clearing things up! Good to know CN1 is making effort to reach all platforms. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffirst-uwp-app-and-the-way-forward.html) + + +### **Jaanus Hansen** — September 11, 2016 at 11:01 am ([permalink](https://www.codenameone.com/blog/first-uwp-app-and-the-way-forward.html#comment-22953)) + +> Jaanus Hansen says: +> +> Very cool news, but why images are so blurry on Desktop? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffirst-uwp-app-and-the-way-forward.html) + + +### **Shai Almog** — September 12, 2016 at 4:20 am ([permalink](https://www.codenameone.com/blog/first-uwp-app-and-the-way-forward.html#comment-22947)) + +> Shai Almog says: +> +> I think that’s due to the apps resources. When I originally wrote the app I had a set of cards at a given resolution. It would have meant quite a bit of work to do a new high DPI deck. +> +> Notice that the toolbar icons aren’t blurry. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffirst-uwp-app-and-the-way-forward.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/flamingo-svg-transcoder-revisited.md b/docs/website/content/blog/flamingo-svg-transcoder-revisited.md new file mode 100644 index 0000000000..276fb764a1 --- /dev/null +++ b/docs/website/content/blog/flamingo-svg-transcoder-revisited.md @@ -0,0 +1,106 @@ +--- +title: Flamingo SVG Transcoder Revisited +slug: flamingo-svg-transcoder-revisited +url: /blog/flamingo-svg-transcoder-revisited/ +original_url: https://www.codenameone.com/blog/flamingo-svg-transcoder-revisited.html +aliases: +- /blog/flamingo-svg-transcoder-revisited.html +date: '2019-06-11' +author: Shai Almog +--- + +![Header Image](/blog/flamingo-svg-transcoder-revisited/uidesign.jpg) + +A couple of years ago I wrote about our support for [Flamingo](/blog/flamingo-svg-transcoder.html) which translates static SVG files to Java source files that you can treat as images within Codename One while getting pixel perfect resolution independent results. There were a few minor changes since until a month ago when Steve committed some work to address this [RFE](https://github.com/codenameone/CodenameOne/issues/2797). + +What’s SVG and Why Should I Care? + +If you’re new to SVG here’s a quick primer. There are two types of images: Vector and Raster. Raster is what most of us work with every day. They are our JPEG, GIF, BMP and PNG images. They store the pixels of the image. There are many nuances here but I’ll leave it at that…​ + +Vector images are something completely different. Instead of storing the pixels they store the primitive drawing operations. If we have an image of a triangle, a raster image will store a lot of pixel values representing the triangle whereas a vector image would just store the fact that a triangle is drawn at a specific size in a given coordinate. + +Vector images work great for images that were designed to be vector images e.g. logos, drawings etc. They are useless for things such as photos. They have a couple of big advantages: + + * They are smaller than raster images both on disk and more importantly in RAM + + * They can scale to any size with no degradation in image quality, this is very helpful for mobile apps + +But surprisingly they might not perform as well as a raster image for all cases. This might be offset by the RAM savings so I’d still recommend SVG for most cases. + +Flamingo works by translating SVG’s to Java source code that you can compile in Codename One. This means more elaborate features such as SVG animations are discarded as part of the process. It also means some SVG’s just won’t work. With the new update we added support for a lot of SVG’s and also updated the [flamingo binary distribution](https://github.com/codenameone/flamingo-svg-transcoder/blob/master/flamingo-svg-transcoder-core-1.2-jar-with-dependencies.jar) which we didn’t have in the original project. + +The recent changes include both improvement to the translation process and to the Codename One API. Our updated API now supports features such as paint and gradient drawing which is commonly used in SVG. Specifically Steve added a `Paint` interface, with concrete subclass `LinearGradientPaint` that can be used to fill a shape with a gradient via `Graphics.setColor(Paint)` then `Graphics.fillShape(shape)`. There are quite a few other related changes such as `MultipleGradientPaint` and `AffineTransform`…​ + +With these in place you can convert a lot of typical SVG’s and use them in your app. The big question is whether we’ll integrate this deeper into Codname One by automating this process. Right now we’re not sure about that or how such integration will look. Maybe something similar to the CSS integration. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Durank** — September 16, 2020 at 2:48 pm ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder-revisited.html#comment-24339)) + +> [Durank](https://avatars0.githubusercontent.com/u/16245755?v=4) says: +> +> how can I use svg image in code using flamingo? I have found some examples but without success +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder-revisited.html) + + +### **Shai Almog** — September 17, 2020 at 4:10 am ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder-revisited.html#comment-24337)) + +> Shai Almog says: +> +> They are just images. Instead of loading it you create a class instance and use it as an image. +> “` +> Image img = new SvgImage(); +> “` +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder-revisited.html) + + +### **Durank** — October 20, 2020 at 3:06 pm ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder-revisited.html#comment-24357)) + +> [Durank](https://avatars0.githubusercontent.com/u/16245755?v=4) says: +> +> how can I to reference my image.svg? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder-revisited.html) + + +### **Shai Almog** — October 21, 2020 at 2:09 am ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder-revisited.html#comment-24358)) + +> Shai Almog says: +> +> You just create a new instance of the generated Java source image. It’s an Image. There’s no SVG anymore. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder-revisited.html) + + +### **Durank** — October 21, 2020 at 3:23 pm ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder-revisited.html#comment-24359)) + +> [Durank](https://avatars0.githubusercontent.com/u/16245755?v=4) says: +> +> please provide an example. I never have worked with svg in codenameone. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder-revisited.html) + + +### **Shai Almog** — October 22, 2020 at 10:47 am ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder-revisited.html#comment-24361)) + +> Shai Almog says: +> +> There’s no example. You just create an instance of the generated class. It’s a subclass of Image so acts as an image. +> +> You can see sample usage here: +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder-revisited.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/flamingo-svg-transcoder.md b/docs/website/content/blog/flamingo-svg-transcoder.md new file mode 100644 index 0000000000..74d3ea4c03 --- /dev/null +++ b/docs/website/content/blog/flamingo-svg-transcoder.md @@ -0,0 +1,449 @@ +--- +title: Flamingo SVG Transcoder +slug: flamingo-svg-transcoder +url: /blog/flamingo-svg-transcoder/ +original_url: https://www.codenameone.com/blog/flamingo-svg-transcoder.html +aliases: +- /blog/flamingo-svg-transcoder.html +date: '2017-05-30' +author: Shai Almog +--- + +![Header Image](/blog/flamingo-svg-transcoder/uidesign.jpg) + +SVG (Scalable Vector Graphics) is an XML based image format that represents an image as vectors instead of pixels (raster). An SVG file is represented by the set of lines & shapes that make it and can thus be rendered at any resolution without quality degradation due to scaling. It has some other neat tricks up its sleeve but I’m only going to discuss that specific feature today. + +There was a time where everyone believed SVG will take the world by storm. It found a niche but never really created the revolution everyone expected. Still it’s a pretty valuable tool but unfortunately mobile device support is “spotty” at best…​ + +All mobile devices support SVG in the browser since it is a web standard. However, in the native layer SVG doesn’t work because of too many nuances related to the web that make it really hard to support the full spec in a native app. Android has partial SVG support where it can convert an SVG file to a native drawable during development time and that’s actually a pretty good idea as it removes the overhead of parsing SVG and the need to support the full spec. + +This isn’t a new idea. Swing had a third party tool from Kirill Grouchnikov who implemented a static translator to generate Java2D code from the given SVG. This tool went thru a couple of forks and recently I chose to fork it myself to create a Codename One version which was surprisingly easy. Unlike the Swing version I created an `Image` subclass so the generated code can be used anywhere images are used. + +You can check out [my fork here](https://github.com/codenameone/flamingo-svg-transcoder) it’s very experimental but if there is interest we can probably enhance it significantly. Gradients aren’t supported currently which can impact a lot of things. I think they should be doable though if we put some time into it. + +I converted a standard SVG of duke waving and showed it using this code: + + + Form current = new Form("SVG", new BorderLayout()); + current.add(CENTER, new ScaleImageLabel(new Duke_waving())); + current.show(); + +![Duke waving image](/blog/flamingo-svg-transcoder/svg-duke.png) + +Figure 1. Duke waving image + +You will notice that Dukes nose isn’t red, that’s because it’s a radial gradient in the source SVG. + +The generated `Duke_waving` class looks like this: + + + public class Duke_waving extends com.codename1.ui.Image implements Painter { + private int width, height; + + public Duke_waving() { + super(null); + width = getOrigWidth(); + height = getOrigHeight(); + } + + public Duke_waving(int width, int height) { + super(null); + this.width = width; + this.height = height; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public void scale(int width, int height) { + this.width = width; + this.height = height; + } + + @Override + public Image fill(int width, int height) { + return new Duke_waving(width, height); + } + + @Override + public Image applyMask(Object mask) { + return new Duke_waving(width, height); + } + + @Override + public boolean isAnimation() { + return true; + } + + @Override + public boolean requiresDrawImage() { + return true; + } + + @Override + protected void drawImage(Graphics g, Object nativeGraphics, int x, int y) { + drawImage(g, nativeGraphics, x, y, width, height); + } + + @Override + protected void drawImage(Graphics g, Object nativeGraphics, int x, int y, int w, int h) { + float hRatio = ((float)w) / ((float)getOrigWidth()); + float vRatio = ((float)h) / ((float)getOrigHeight()); + int origX = g.getTranslateX(); + int origY = g.getTranslateY(); + g.translate(-origX, -origY); + g.scale(hRatio, vRatio); + int tx = (int)(((float)x) / hRatio); + int ty = (int)(((float)y) / vRatio); + g.translate(tx, ty); + paint(g); + g.resetAffine(); + g.translate(origX - g.getTranslateX(), origY - g.getTranslateY()); + } + + private static void paint(Graphics g) { + int origAlpha = g.getAlpha(); + Stroke baseStroke; + Shape shape; + g.setAntiAliased(true); + g.setAntiAliasedText(true); + + // + + // _0 + + // _0_0 + shape = new GeneralPath(); + ((GeneralPath) shape).moveTo(48.859, 43.518); + ((GeneralPath) shape).curveTo(57.283, 61.158, 51.595, 184.35, 41.731003, 227.55); + ((GeneralPath) shape).curveTo(31.867002, 270.822, 22.003002, 325.83002, 19.699003, 372.126); + ((GeneralPath) shape).curveTo(18.691004, 391.854, 21.715004, 399.63, 34.603004, 399.63); + ((GeneralPath) shape).curveTo(57.355003, 399.63, 86.227005, 351.678, 122.443, 352.758); + ((GeneralPath) shape).curveTo(158.731, 353.83798, 170.251, 407.766, 187.24301, 407.406); + ((GeneralPath) shape).curveTo(204.23502, 407.04602, 217.91501, 401.142, 218.059, 348.654); + ((GeneralPath) shape).curveTo(218.563, 191.981, 87.235, 64.973, 48.859, 43.518); + ((GeneralPath) shape).lineTo(48.859, 43.518); + ((GeneralPath) shape).lineTo(48.859, 43.518); + ((GeneralPath) shape).lineTo(48.859, 43.518); + ((GeneralPath) shape).closePath(); + + g.setColor(0); + g.fillShape(shape); + + // _0_1 + shape = new GeneralPath(); + ((GeneralPath) shape).moveTo(162.763, 168.726); + ((GeneralPath) shape).curveTo(170.755, 182.19, 191.131, 171.82199, 191.995, 156.63); + ((GeneralPath) shape).curveTo(192.859, 141.438, 190.627, 122.286, 180.763, 121.56601); + ((GeneralPath) shape).curveTo(170.899, 120.84601, 163.843, 110.98201, 153.979, 110.26201); + ((GeneralPath) shape).curveTo(144.115, 109.54201, 133.531, 119.406006, 128.923, 106.30201); + ((GeneralPath) shape).curveTo(124.315, 93.19801, 141.307, 87.65401, 153.979, 85.56601); + ((GeneralPath) shape).curveTo(142.675, 74.26201, 136.05101, 61.73401, 131.08301, 48.70201); + ((GeneralPath) shape).curveTo(126.115005, 35.670013, 122.44301, 23.718012, 136.339, 18.60601); + ((GeneralPath) shape).curveTo(150.235, 13.494011, 149.08301, 39.77401, 164.99501, 51.79801); + ((GeneralPath) shape).curveTo(160.31502, 34.086014, 158.587, 26.742012, 158.947, 16.44601); + ((GeneralPath) shape).curveTo(159.307, 6.150009, 158.587, -1.6979885, 173.203, 0.31801033); + ((GeneralPath) shape).curveTo(187.819, 2.3340104, 181.483, 32.71801, 192.85901, 45.102013); + ((GeneralPath) shape).curveTo(196.315, 33.366013, 198.40302, 18.462013, 206.755, 12.342014); + ((GeneralPath) shape).curveTo(215.107, 6.2220154, 234.115, 6.0780144, 222.01901, 31.206015); + ((GeneralPath) shape).curveTo(209.92302, 56.334015, 225.54701, 69.94202, 221.87502, 89.74201); + ((GeneralPath) shape).curveTo(218.20302, 109.54201, 206.82701, 105.94202, 201.93102, 118.68601); + ((GeneralPath) shape).curveTo(197.03502, 131.43001, 204.81102, 160.44601, 195.59502, 173.47801); + ((GeneralPath) shape).curveTo(186.37901, 186.51001, 184.72302, 206.52602, 190.69902, 222.51001); + ((GeneralPath) shape).curveTo(172.339, 205.374, 162.763, 168.726, 162.763, 168.726); + ((GeneralPath) shape).lineTo(162.763, 168.726); + ((GeneralPath) shape).lineTo(162.763, 168.726); + ((GeneralPath) shape).lineTo(162.763, 168.726); + ((GeneralPath) shape).closePath(); + + g.fillShape(shape); + + // _0_2 + shape = new GeneralPath(); + ((GeneralPath) shape).moveTo(48.355, 185.646); + ((GeneralPath) shape).curveTo(40.939, 236.478, 15.162998, 242.526, 13.867001, 263.622); + ((GeneralPath) shape).curveTo(12.571001, 284.71802, 20.707, 286.734, 20.203001, 306.246); + ((GeneralPath) shape).curveTo(19.699001, 325.758, 2.3470001, 333.678, 0.25900078, 344.262); + ((GeneralPath) shape).curveTo(-1.8289986, 354.84598, 9.187001, 358.22998, 15.595001, 358.22998); + ((GeneralPath) shape).curveTo(22.003002, 358.22998, 28.411001, 330.15, 31.003002, 312.29398); + ((GeneralPath) shape).curveTo(33.595, 294.43796, 22.507002, 283.92596, 22.507002, 271.68597); + ((GeneralPath) shape).curveTo(22.507002, 259.44598, 38.563004, 237.05397, 35.611, 256.70996); + ((GeneralPath) shape).curveTo(48.931, 235.686, 55.268, 208.901, 48.355, 185.646); + ((GeneralPath) shape).lineTo(48.355, 185.646); + ((GeneralPath) shape).lineTo(48.355, 185.646); + ((GeneralPath) shape).lineTo(48.355, 185.646); + ((GeneralPath) shape).closePath(); + + g.fillShape(shape); + + // _0_3 + shape = new GeneralPath(); + ((GeneralPath) shape).moveTo(58.292, 205.013); + ((GeneralPath) shape).curveTo(52.676, 232.517, 17.612, 386.09302, 35.468002, 388.037); + ((GeneralPath) shape).curveTo(53.324005, 389.981, 78.740005, 340.517, 120.356, 340.87698); + ((GeneralPath) shape).curveTo(162.044, 341.23697, 178.46, 396.317, 188.612, 395.95697); + ((GeneralPath) shape).curveTo(198.764, 395.597, 205.45999, 399.55698, 206.54, 337.49298); + ((GeneralPath) shape).curveTo(207.62, 275.429, 169.74799, 196.15698, 147.35599, 161.23698); + ((GeneralPath) shape).curveTo(116.971, 163.181, 84.283, 187.518, 58.292, 205.013); + ((GeneralPath) shape).lineTo(58.292, 205.013); + ((GeneralPath) shape).lineTo(58.292, 205.013); + ((GeneralPath) shape).lineTo(58.292, 205.013); + ((GeneralPath) shape).closePath(); + + g.setColor(0xffffff); + g.fillShape(shape); + + // _0_4 + + // _0_4_0 + + // _0_4_1 + shape = new GeneralPath(); + ((GeneralPath) shape).moveTo(147.082, 171.533); + ((GeneralPath) shape).curveTo(145.42, 154.33801, 132.675, 143.545, 116.187, 140.906); + ((GeneralPath) shape).curveTo(100.263, 138.35701, 82.927, 145.904, 71.77899, 157.052); + ((GeneralPath) shape).curveTo(59.24099, 169.59, 58.73999, 187.03, 67.51899, 201.88501); + ((GeneralPath) shape).curveTo(76.17999, 216.542, 95.36599, 221.38602, 111.081985, 217.72002); + ((GeneralPath) shape).curveTo(132.588, 212.705, 148.48, 193.896, 147.082, 171.533); + + g.setColor(0); + g.fillShape(shape); + + // _0_4_2 + shape = new GeneralPath(); + ((GeneralPath) shape).moveTo(139.162, 177.941); + ((GeneralPath) shape).curveTo(137.669, 193.568, 125.215004, 206.12299, 110.218, 209.765); + ((GeneralPath) shape).curveTo(94.348, 213.619, 76.825, 207.508, 71.122, 191.189); + ((GeneralPath) shape).curveTo(68.21, 182.857, 68.752, 174.31, 73.759, 166.991); + ((GeneralPath) shape).curveTo(77.982, 160.81999, 84.792, 155.991, 91.538, 152.925); + ((GeneralPath) shape).curveTo(105.462006, 146.599, 125.37, 145.896, 135.069, 160.002); + ((GeneralPath) shape).curveTo(138.744, 165.348, 139.387, 171.641, 139.162, 177.941); + + g.setColor(0xffffffff); + g.fillShape(shape); + g.setColor(0); + baseStroke = new Stroke(1, 0, 0, 4); + g.drawShape(shape, baseStroke); + + + g.setAlpha(origAlpha); + g.resetAffine(); + } + + /** + * Returns the X of the bounding box of the original SVG image. + * + * @return The X of the bounding box of the original SVG image. + */ + public static int getOrigX() { + return 0; + } + + /** + * Returns the Y of the bounding box of the original SVG image. + * + * @return The Y of the bounding box of the original SVG image. + */ + public static int getOrigY() { + return 0; + } + + /** + * Returns the width of the bounding box of the original SVG image. + * + * @return The width of the bounding box of the original SVG image. + */ + public static int getOrigWidth() { + return 226; + } + + /** + * Returns the height of the bounding box of the original SVG image. + * + * @return The height of the bounding box of the original SVG image. + */ + public static int getOrigHeight() { + return 408; + } + + @Override + public void paint(Graphics g, Rectangle rect) { + drawImage(g, null, rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); + } + } + +### SVG vs. Font Icons/Material Fonts + +You can’t color SVG’s dynamically and they will probably never match the speed/convenience of font icons. For most use cases you should probably use the font icons or material icons. However, if you need a design element or icon that is vector based and has multiple colors this might be an interesting option. + +In terms of performance it’s hard to know how well SVG will perform. If you have an image with a fixed size on device you can just convert it to a raster in runtime and use that to avoid potential performance overhead. + +### Moving Forward + +This depends a lot on demand/pull requests and needs. Supporting gradients will open up a lot of use cases. + +It might be interesting to allow manipulation of some SVG object states as well…​ This might be required if we want to support SVG animations which would provide a great deal of benefit e.g. for animations in the style of Androids menu button animating to a back button etc. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — November 20, 2017 at 4:56 pm ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-21633)) + +> I’m interested in converting an svg scalable logo to Codename One code, but… is the link you provided correct? There is no mention of Codename One: +> [https://github.com/ebourg/f…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + + +### **Shai Almog** — November 21, 2017 at 12:33 pm ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-21533)) + +> Ugh, thanks! It’s [http://github.com/codenameo…]() +> I’ll fix it in the post. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + + +### **Angelo** — June 23, 2020 at 5:31 pm ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-24281)) + +> Angelo says: +> +> If I understand, the utility converts an SVG file that uses a reduced set of features to real Java code. Is it possible just to create a XML file to be loaded from resources with curves, lines, moves and so on? You could create a class like ImageFromSVGSubset and instances would be created with sort of new ImageFromSVGSubset(“id”). The xml has not to be an official format, just used by developers in Codename One that want to use the transcoder and that know what they are doing. I think it should take just one hour of development for you, starting from the current fork. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + + +### **Shai Almog** — June 24, 2020 at 2:45 am ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-21424)) + +> Shai Almog says: +> +> No it’s harder. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + + +### **Angelo** — June 24, 2020 at 7:11 am ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-24280)) + +> Angelo says: +> +> I take the occasion to inform you about a bug. In the code this line is encountered: +> shape = new Rectangle2D.Double(0.008569182828068733, 0.0054579987190663815, 6.3905863761901855, 6.390747547149658); +> +> Some characters from a method signature went into the output. +> I had to manually fix it but it is a minor thing. +> I had problems in some cases with the paint method that is annotated @Override +> Thank you. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + + +### **Durank** — October 21, 2020 at 3:20 pm ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-24344)) + +> [Durank](https://avatars0.githubusercontent.com/u/16245755?v=4) says: +> +> Please provide a solutions to use SVG images more easy. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + + +### **Durank** — October 21, 2020 at 4:33 pm ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-24360)) + +> [Durank](https://avatars0.githubusercontent.com/u/16245755?v=4) says: +> +> I did all steps in the flamingo page and I can’t see the generated java code to my svg image +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + + +### **Shai Almog** — October 22, 2020 at 10:48 am ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-24362)) + +> Shai Almog says: +> +> Does it print out that it’s processing the SVGs? What’s printed? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + + +### **Duran k** — October 22, 2020 at 3:10 pm ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-24364)) + +> [Duran k](https://lh3.googleusercontent.com/a-/AOh14GhIAakAlC4gLyRHwDzKuv6MUG2CDvLghf3zUAG8yA=s96-c) says: +> +> nothing +> Microsoft Windows [Version 10.0.19041.572] +> (c) 2020 Microsoft Corporation. All rights reserved. +> +> C:Usersdesarrollo1>cd F:data_kdpprogramsCodenameOneutils_programssvg +> +> C:Usersdesarrollo1>f: +> +> F:data_kdpprogramsCodenameOneutils_programssvg>dir +> Volume in drive F is data_kdp +> Volume Serial Number is 48F9-3B10 +> +> Directory of F:data_kdpprogramsCodenameOneutils_programssvg +> +> 21/10/2020 12:38 p. m. . +> 21/10/2020 12:38 p. m. .. +> 20/10/2020 10:47 a. m. 38,154 automobile_automotive_car.svg +> 21/10/2020 12:38 p. m. ebourg-flamingo-svg-transcoder-1.2-3-gc12f421 +> 21/10/2020 12:38 p. m. 398,372 ebourg-flamingo-svg-transcoder-1.2-3-gc12f421.zip +> 21/10/2020 11:25 a. m. 2,948,454 flamingo-svg-transcoder-core-1.2-jar-with-dependencies.jar +> 21/10/2020 11:35 a. m. 4,642,088 fondo.svg +> 21/10/2020 12:06 p. m. 50,833 method-draw-image.svg +> 21/10/2020 12:23 p. m. myfiles +> 5 File(s) 8,077,901 bytes +> 4 Dir(s) 111,844,356,096 bytes free +> +> F:data_kdpprogramsCodenameOneutils_programssvg>java -jar flamingo-svg-transcoder-core-1.2-jar-with-dependencies.jar /myfiles fondo.svg +> +> F:data_kdpprogramsCodenameOneutils_programssvg> +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + + +### **Shai Almog** — October 23, 2020 at 6:53 am ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-24356)) + +> Shai Almog says: +> +> The arguments should be the current directory followed by package name. So something like: +> “` +> . com.mypackage.svg +> “` +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + + +### **Duran k** — October 23, 2020 at 6:30 pm ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-24363)) + +> [Duran k](https://lh3.googleusercontent.com/a-/AOh14GhIAakAlC4gLyRHwDzKuv6MUG2CDvLghf3zUAG8yA=s96-c) says: +> +> I don’t know what is the package name that you said. This documentation isn’t very clear. Please provide a Documentation more clear. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + + +### **Shai Almog** — October 24, 2020 at 5:38 am ([permalink](https://www.codenameone.com/blog/flamingo-svg-transcoder.html#comment-24365)) + +> Shai Almog says: +> +> It’s your package name. This is a code generator. It generates source code to a specific package name. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflamingo-svg-transcoder.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/flat-themes-dpis-static-initializers.md b/docs/website/content/blog/flat-themes-dpis-static-initializers.md new file mode 100644 index 0000000000..e88547787e --- /dev/null +++ b/docs/website/content/blog/flat-themes-dpis-static-initializers.md @@ -0,0 +1,132 @@ +--- +title: Flat Themes, DPI's & Static Initializers +slug: flat-themes-dpis-static-initializers +url: /blog/flat-themes-dpis-static-initializers/ +original_url: https://www.codenameone.com/blog/flat-themes-dpis-static-initializers.html +aliases: +- /blog/flat-themes-dpis-static-initializers.html +date: '2015-05-12' +author: Shai Almog +--- + +![Header Image](/blog/flat-themes-dpis-static-initializers/flat-blue-theme.png) + +With the release of 3.0 we were overwhelmed with a lot of last minute features and improvements. It seems +that we neglected to mention a lot of features that made it into the final 3.0 product. +One of the nicest new features is a set of new flat themes with various colors in the designer and the project +wizard. We found that a lot of developers prefer themes with more control over the look, themes that look +more similar across platform yet have a more modern “flat” feel. + +A long time request has been to add the additional DPI resolutions we added for higher density devices into +the designer tool. We now support these additional densities in the designer tool both in the multi image import +and when editing a specific resolution. + +On a different subject, we noticed a couple of developers had one of those hard to track down bugs that boiled +down to using the FileSystemStorage API from static context. E.g. this: + + + public static final String MY_HOME_DIR = FileSystemStorage.getInstance().getAppHomePath(); + +This seems like code that should work and annoyingly enough it works on the simulator. However, because of the +way classloaders work this code will probably fail on devices. Static context can be initialized at any time and since +the initialization of the implementation code might occur after the initialization of static context the static variable +might not work well… +You should pay attention to such code where you invoke implementation classes from static context and try to avoid +it, ideally we’d make this fail on the simulator but that is a bit tricky. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **rhg1968** — May 13, 2015 at 6:48 pm ([permalink](https://www.codenameone.com/blog/flat-themes-dpis-static-initializers.html#comment-22262)) + +> rhg1968 says: +> +> I see the new templates in NetBeans but not in IntelliJ 14.1.3 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflat-themes-dpis-static-initializers.html) + + +### **Shai Almog** — May 14, 2015 at 6:52 pm ([permalink](https://www.codenameone.com/blog/flat-themes-dpis-static-initializers.html#comment-22192)) + +> Shai Almog says: +> +> Can you file an issue on that? +> We’ll need to add them there too. As a workaround you can just create a new project with a native theme. Open the designer tool, delete the “Theme” entry and create a new theme, you should have these options there assuming you are using the latest plugin. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflat-themes-dpis-static-initializers.html) + + +### **rhg1968** — May 14, 2015 at 7:01 pm ([permalink](https://www.codenameone.com/blog/flat-themes-dpis-static-initializers.html#comment-22229)) + +> rhg1968 says: +> +> Thanks for the reply. I just put the issue on GitHub. I am using plugin 3.0.2 and I don’t have any updates so I believe I am using the latest. I also refreshed the libraries but I don’t see the theme in the GUI builder if I try to add a new theme to an existing project. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflat-themes-dpis-static-initializers.html) + + +### **Shai Almog** — May 15, 2015 at 9:48 am ([permalink](https://www.codenameone.com/blog/flat-themes-dpis-static-initializers.html#comment-22044)) + +> Shai Almog says: +> +> Its possible the IDEA plugin doesn’t update the designer to the latest version too. We’ll look into it as part of the bug. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflat-themes-dpis-static-initializers.html) + + +### **J.C** — May 15, 2015 at 3:04 pm ([permalink](https://www.codenameone.com/blog/flat-themes-dpis-static-initializers.html#comment-24173)) + +> J.C says: +> +> Shai, to clarify about static initializers for some people, it would be clearer to enclose the statement you illustrated inside static {}. +> +> For example, is this what you mean? +> +> Avoid: +> +> public static final String MY_HOME_DIR; +> static { +> MY_HOME_DIR = FileSystemStorage.getInstance().getAppHomePath(); +> } +> +> If not, please clarify and include an example that says: Don’t {….} and Do{…} etc..if its not too much trouble :). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflat-themes-dpis-static-initializers.html) + + +### **Shai Almog** — May 15, 2015 at 4:24 pm ([permalink](https://www.codenameone.com/blog/flat-themes-dpis-static-initializers.html#comment-22354)) + +> Shai Almog says: +> +> That would be a problem. Use a getter that invokes that method. Don’t store it in that static context. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflat-themes-dpis-static-initializers.html) + + +### **J.C** — May 15, 2015 at 5:45 pm ([permalink](https://www.codenameone.com/blog/flat-themes-dpis-static-initializers.html#comment-22239)) + +> J.C says: +> +> Hmm, so what you are saying is, in general, avoid storing values returned by methods that is initializing underlying platform implementations into static variables when a class is created? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflat-themes-dpis-static-initializers.html) + + +### **Shai Almog** — May 16, 2015 at 8:51 am ([permalink](https://www.codenameone.com/blog/flat-themes-dpis-static-initializers.html#comment-22263)) + +> Shai Almog says: +> +> No. Avoid access to Codename One API’s from static context since it might get initialized before the Codename One API gets initialized. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflat-themes-dpis-static-initializers.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/floating-button.md b/docs/website/content/blog/floating-button.md new file mode 100644 index 0000000000..c8d49391ba --- /dev/null +++ b/docs/website/content/blog/floating-button.md @@ -0,0 +1,370 @@ +--- +title: Floating Button +slug: floating-button +url: /blog/floating-button/ +original_url: https://www.codenameone.com/blog/floating-button.html +aliases: +- /blog/floating-button.html +date: '2016-09-13' +author: Shai Almog +--- + +![Header Image](/blog/floating-button/floating-action.png) + +The material design floating action button is a powerful tool for promoting an action within your application. Quite +a few Codename One developers implemented with own interpretation of this UI element and with the coming update +we will have an official implementation. + +The `FloatingActionButton` is a round button that resides on top of the UI typically in the bottom right hand side. +It has a drop shadow to distinguish it from the UI underneath and it can hide two or more additional actions under +the surface. E.g. we can create a simple single click button such as this: + + + FloatingActionButton fab = FloatingActionButton.createFAB(FontImage.MATERIAL_ADD); + fab.addActionListener(e -> ToastBar.showErrorMessage("Not implemented yet...")); + fab.bindFabToContainer(form.getContentPane()); + +Which will place a `+` sign button that will perform the action. Alternatively we can create a nested action +where a click on the button will produce a submenu for users to pick from e.g.: + + + FloatingActionButton fab = FloatingActionButton.createFAB(FontImage.MATERIAL_ADD); + fab.createSubFAB(FontImage.MATERIAL_PEOPLE, ""); + fab.createSubFAB(FontImage.MATERIAL_IMPORT_CONTACTS, ""); + fab.bindFabToContainer(form.getContentPane()); + +![FloatingActionButton with submenu expanded](/blog/floating-button/floating-action.png) + +Figure 1. FloatingActionButton with submenu expanded + +Those familiar with this widget know that there are many nuances to this UI that we might implement/expose +in the future. At the moment we chose to keep the API simple and minimal for the common use cases and refine +it based on demand. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — September 14, 2016 at 3:10 pm ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-22898)) + +> Another nice one! Does the “+” also animate to an “x” when opening the sub-menu? 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Lukman Javalove Idealist Jaji** — September 14, 2016 at 3:15 pm ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-22986)) + +> Lukman Javalove Idealist Jaji says: +> +> So many good things coming out this week…i m happy… Am I the only developer who refreshes the homepage daily to check new blog posts? I find these articles and tutorials more useful. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Bayu Sanjaya** — September 14, 2016 at 7:32 pm ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-22922)) + +> Bayu Sanjaya says: +> +> Hi I got this error when trying to add fab into my container (not by form.getcontentPane()). +> java.lang.IllegalArgumentException: Component is already contained in Container: Container[x=0 y=0 width=0 height=0, layout = LayeredLayout, scrollableX = false, scrollableY = false, components = [Container, Container]] +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — September 15, 2016 at 3:58 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-22788)) + +> Shai Almog says: +> +> That’s one of the nuances I was referring to. I have some thoughts on how to do these subtle animations but I don’t think they will work nicely with the FontImage class. I want to do it in a way that is elegant. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — September 15, 2016 at 4:00 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-22908)) + +> Shai Almog says: +> +> I think I changed the sample code before posting and broke it, I’ll update the article later today. Notice that this will be available only on the Friday update. What you have right now is experimental. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — September 15, 2016 at 4:01 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-22708)) + +> Shai Almog says: +> +> Thanks! +> FYI we have an RSS feed so you can just subscribe to that or use RSS to email services such as ifttt +> [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Bayu Sanjaya** — September 15, 2016 at 4:04 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-22979)) + +> Bayu Sanjaya says: +> +> Hi, I use a workaround for this one, I use a container for fab.bindFabToContainer(myContainer) and add it into main form. I think it’s stable enough to implement even it is still experimental. But I’m not really sure. +> Btw, how to change the color, i tried with UIID but the button changed into square. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — September 15, 2016 at 4:59 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-22685)) + +> Shai Almog says: +> +> I’ve given this some thought and decided to just change the implementation so the code above “just works”. Set the background color of the UIID: FloatingActionButton +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Jérémy MARQUER** — September 15, 2016 at 7:17 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-22743)) + +> Jérémy MARQUER says: +> +> You’re not the only one 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Andreas Grätz** — September 17, 2016 at 3:47 pm ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23102)) + +> Andreas Grätz says: +> +> FABs are great! But what if we have more FABs as space on the screen? The list of FABs and sub-FABs isn’t scrollable. We are working on an app, which loads the business logic from an application server. We don’t now the final count of commands. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — September 18, 2016 at 4:05 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23113)) + +> Shai Almog says: +> +> Google’s design explicitly forbids scrolling. +> +> They consider these to be “speed dial” which means you pick the top 4 entries and anything beyond that should reside in a “…” more action. This is indeed more intuitive for such cases. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **disqus** — September 30, 2016 at 9:42 pm ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23041)) + +> disqus says: +> +> How do I add a floating button to a Gui Builder generated form? How do I add any initialization code on Gui Builder generated forms since init method is generated code and is not supposed to be edited? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — October 1, 2016 at 1:30 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-22834)) + +> Shai Almog says: +> +> You can edit the constructors just fine so code that runs before the init can go before it and code that runs after can go after the init method. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **ShmuDesign** — March 1, 2017 at 8:11 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23177)) + +> ShmuDesign says: +> +> Hi, this is good, but is it possible to remove the shadow or change the thickness ? Because I have a strange square ! ([http://shmu.fr/wooz/square-…]() I change the color to show what append) that problem appear only on IOS ! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — March 2, 2017 at 8:35 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23224)) + +> Shai Almog says: +> +> Hi, +> you can customize every aspect in the style including the shadow. I think the padding for the component might be too small causing the shadow to crop but if I’m wrong then it might be a clipping bug we need to fix in which case we’ll need to file an issue +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Mo** — June 24, 2017 at 10:40 pm ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23479)) + +> Mo says: +> +> Hi, I have been having trouble trying to show the FloatingActionButton when switching Locale (RTL), while the LTR works as expected, below is the code am currently using to align Right, Center, +> ` +> fab.bindFabToContainer(root, Component.RIGHT, Component.CENTER); +> ` +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — June 25, 2017 at 4:45 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23483)) + +> Shai Almog says: +> +> By convention in Codename One right becomes left in RTL mode unless you explicitly disable RTL behavior for that component. I don’t think we tested RTL on the FAB so it might be broken there. I’d expect that code to place the FAB on the left side in Codename One. I’m guessing it doesn’t? How does it look? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Mo** — June 25, 2017 at 1:28 pm ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23508)) + +> Mo says: +> +> Hi Shai, thank you for getting back to me, when changing to Arabic locale (RTL) it’s not showing at all and unlike when it’s LTR direction, keeping in mind that, the root container is correctly changing direction!! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Mo** — June 25, 2017 at 11:08 pm ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23593)) + +> Mo says: +> +> Hi Shai, any thoughts as to when this will be looked at or fixed, since I am planning to utilise this component on most of my Containers ?? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — June 26, 2017 at 4:37 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23562)) + +> Shai Almog says: +> +> Hi, +> first you need to file an issue and then we need to set a priority. We’re just releasing 3.7 so it will probably take a while if it’s even scheduled for 3.8 as that release is already pretty full with issues. +> Since this issue probably existed since 2016 without a report that probably indicates the low priority of this issue. +> +> I think you might be able to workaround this by disabling RTL on the content pane and aligning the FAB to the left. +> +> FYI You can also try to fix this issue yourself and submit a pull request which is excellent practice. I have a tutorial about that here: [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Mo** — July 2, 2017 at 10:53 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23460)) + +> Mo says: +> +> Apologies for the late reply!!, +> Issue filed for this at ([https://github.com/codename…]()), and have been trying to implement the workaround suggested, sadly this caused my other component layout to miss-behave, thus, I would rather wait for the fix and hopefully not too long! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — July 3, 2017 at 3:13 pm ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23537)) + +> Shai Almog says: +> +> If you only apply the LTR mode to the button and the layered layout (not the other components) it shouldn’t impact anything else. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Tommy Mogaka** — July 12, 2018 at 10:51 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23927)) + +> Tommy Mogaka says: +> +> Hi, +> How do I add an action to each of the submenu items? I have +> been able to create a floating action button with three submenus but when I +> add an actionlister it is fires on the main button and not the sub +> buttons. +> +> FloatingActionButton fabtn = FloatingActionButton.createFAB(FontImage.MATERIAL_ADD); +> fabtn.getAllStyles().setFont(font_small_bold); +> fabtn.getAllStyles().setFgColor(0xffd800); +> fabtn.getAllStyles().setBgColor(0xffd800); +> +> fabtn.addActionListener(e -> ToastBar.showErrorMessage(“Add Personel Not implemented yet…”)); +> fabtn.createSubFAB(FontImage.MATERIAL_PEOPLE, “Add Personel”).getAllStyles().setBgColor(0xffd800); +> fabtn.setTextPosition(BOTTOM); +> +> fabtn.addActionListener(f -> ToastBar.showErrorMessage(“Add Equipment Not implemented yet…”)); +> fabtn.createSubFAB(FontImage.MATERIAL_COMMENT, “Add Equipment”).getAllStyles().setBgColor(0xffd800); +> fabtn.setTextPosition(BOTTOM); +> +> Also, I can’t seem to get the submenu text to show! Finally, how do I style the submenu items individually e.g. text position or font colour? I have only been able to change the icon colours for the main button and the sub buttons as shown above. +> +> Thanks! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — July 13, 2018 at 4:51 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-23847)) + +> Shai Almog says: +> +> createSubFab returns its own FAB instance. You need to bind your listener to that instance. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Tommy Mogaka** — February 3, 2019 at 1:34 pm ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-24015)) + +> Tommy Mogaka says: +> +> Hi Shai.. I was able to a create a separate ActionListener for each SubFab but how do I style each SubFub separately? +> +> Below is what I have done but the way I’ve done it doesn’t allow changing the BgColor for each SubFub as previously. Could you please show my how I can be able to do so? +> +> fabtn.createSubFAB(FontImage.MATERIAL_HELP, “Help”).addActionListener(new ActionListener() +> { +> @Override +> public void actionPerformed(ActionEvent evt) +> { +> ToastBar.showErrorMessage(“Help button pressed…”); +> } +> }); +> +> fabtn.createSubFAB(FontImage.MATERIAL_BUILD, “Settings”).addActionListener(new ActionListener() +> { +> @Override +> public void actionPerformed(ActionEvent evt) +> { +> ToastBar.showErrorMessage(“Admin button pressed…”); +> } +> }); +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — February 4, 2019 at 3:31 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-24021)) + +> Shai Almog says: +> +> Instead of adding the action listener save the returned instance of the subfab and then add the action listener. Then customize the color on that returned instance. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Tommy Mogaka** — February 4, 2019 at 7:31 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-24027)) + +> Tommy Mogaka says: +> +> Thanks Shai for the prompt reply… I will have to expose that my Java skills are quiet questionable as I am mostly self-taught and so I am not familiar with some concepts e.g. how to return an instance of a component. +> +> Could you please share some code snippet on how I can return an instance of a Subfab and how to save and style it? Many thanks! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + + +### **Shai Almog** — February 5, 2019 at 3:10 am ([permalink](https://www.codenameone.com/blog/floating-button.html#comment-24053)) + +> Shai Almog says: +> +> `FloatingActionButton subFabHelp = fabtn.createSubFAB(FontImage.MATERIAL_HELP, “Help”); +> subFabHelp.addActionListener(…); +> subFabHelp.setUIID(“SubFabStyle”); +> ` +> +> Or similar. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffloating-button.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/flurry-interstitial-ads-analytics.md b/docs/website/content/blog/flurry-interstitial-ads-analytics.md new file mode 100644 index 0000000000..4ee4d4399f --- /dev/null +++ b/docs/website/content/blog/flurry-interstitial-ads-analytics.md @@ -0,0 +1,68 @@ +--- +title: Flurry Interstitial Ads & Analytics +slug: flurry-interstitial-ads-analytics +url: /blog/flurry-interstitial-ads-analytics/ +original_url: https://www.codenameone.com/blog/flurry-interstitial-ads-analytics.html +aliases: +- /blog/flurry-interstitial-ads-analytics.html +date: '2015-03-01' +author: Shai Almog +--- + +![Header Image](/blog/flurry-interstitial-ads-analytics/flurry_logo.jpg) + +![](/blog/flurry-interstitial-ads-analytics/flurry_logo.jpg) + +Chen was working with a customer that needed some specific ad network support and decided to open source +some of that work. We now have integration with Flurry both for its ads and [analytics](https://developer.yahoo.com/analytics/) +support both of which are pretty cool and have some distinct advantages over the current Google equivalents. + +You can download the project [here](https://code.google.com/p/flurry-codenameone/), Chen wrote a +very detailed [usage tutorial in the wiki page](https://code.google.com/p/flurry-codenameone/wiki/Usage) +so there is no point in repeating it. + +One of the big advantages here is that the flurry integration is a cn1lib project which makes it a great integration reference +tutorial. We now have 2 ad networks integrated in that way which means that if you want to integrate another one you have a beaten path to follow. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — March 2, 2015 at 1:29 pm ([permalink](https://www.codenameone.com/blog/flurry-interstitial-ads-analytics.html#comment-22119)) + +> Anonymous says: +> +> This looks interesting! +> +> Questions that come to mind: +> +> 1\. Is there any reason why the methods setUserID, setAge, and setGender are not exposed via FlurryManager? I see that they are defined in FlurryNative so I would expect that in the manager class as well. +> +> 2\. Are there any restrictions for using crash reporting (cf. the cn1 in-built feature that requires a Pro license)? +> +> Cheers +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflurry-interstitial-ads-analytics.html) + + +### **Anonymous** — March 3, 2015 at 2:04 am ([permalink](https://www.codenameone.com/blog/flurry-interstitial-ads-analytics.html#comment-22295)) + +> Anonymous says: +> +> 1\. Those are probably an omission due to lack of information from the customer. +> +> 2\. The crash reporting in flurry won’t give you any valuable information since Codename One apps are stripped by default so you will get giberrish. There are other complexities involved as well. +> +> With the new VM we would like to upgrade the crash reporting capability to a level that would provide you with Java thread states which is far more useful than anything Flurry has for a Java developer. But that is still a way off. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fflurry-interstitial-ads-analytics.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/folk-dancing-and-general-updates.md b/docs/website/content/blog/folk-dancing-and-general-updates.md new file mode 100644 index 0000000000..6586967823 --- /dev/null +++ b/docs/website/content/blog/folk-dancing-and-general-updates.md @@ -0,0 +1,87 @@ +--- +title: Folk Dancing And General Updates +slug: folk-dancing-and-general-updates +url: /blog/folk-dancing-and-general-updates/ +original_url: https://www.codenameone.com/blog/folk-dancing-and-general-updates.html +aliases: +- /blog/folk-dancing-and-general-updates.html +date: '2013-08-25' +author: Shai Almog +--- + +![Header Image](/blog/folk-dancing-and-general-updates/hqdefault.jpg) + + + +Who would have thought Hungarian folk dance would be so entertaining! Can’t. stop. watching…. + + + +Its been a busy week mostly spent on updating the build server code so its iOS 7 ready, during that time we also managed to get some other things done… These are some of the highlights: + +You may recall the +[ +ImageViewer class that I mentioned a while back +](http://www.codenameone.com/3/post/2013/08/in-a-pinch.html) +, it will now be a part of the designer and has some small improvements to its event handling as well as keyboard handling. + +We now have a new set of image rotation API’s designed for camera images. These API’s can rotate or flip an image by square angles, which is important for rotating an image that isn’t a perfect square (e.g. taken by camera). These API’s are really simple to use e.g.: image.rotate90Degrees(true); + +Where the boolean argument indicates whether the image is opaque (e.g. for the case of a camera image). There are also methods for 180 and 270 degrees as well as vertical and horizontal flip methods. + +Up until recently we always told people to avoid the scaled method as much as possible, the main issue was that an image gets decoded and then is very expensive to hold in RAM. This is not necessarily the case anymore. Now if you invoke the scaled() method on an EncodedImage (assuming you are not on a feature phone) the ImageIO class will be used to re-encode the resulting image and allow you the same benefits as any other encoded image. + +We still don’t recommend scaled since its still less efficient than drawing and not as sharp as multi image. It will now also be slightly slower but it will have a better memory footprint. + +We also added a feature that allows you to create an encoded image from ARGB data, again using the ImageIO class, this isn’t guaranteed to work (since ImageIO doesn’t necessarily exist in all devices) but when it does it should be more efficient for most use cases. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — August 27, 2013 at 3:46 am ([permalink](https://www.codenameone.com/blog/folk-dancing-and-general-updates.html#comment-24253)) + +> Anonymous says: +> +> ImageViewer is deleted in new version have any class for instead for it ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffolk-dancing-and-general-updates.html) + + +### **Anonymous** — August 27, 2013 at 4:51 am ([permalink](https://www.codenameone.com/blog/folk-dancing-and-general-updates.html#comment-21793)) + +> Anonymous says: +> +> No its not, its under components. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffolk-dancing-and-general-updates.html) + + +### **Anonymous** — August 29, 2013 at 7:49 am ([permalink](https://www.codenameone.com/blog/folk-dancing-and-general-updates.html#comment-21736)) + +> Anonymous says: +> +> Tell me your scaled() works for j2me. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffolk-dancing-and-general-updates.html) + + +### **Anonymous** — August 29, 2013 at 4:27 pm ([permalink](https://www.codenameone.com/blog/folk-dancing-and-general-updates.html#comment-21707)) + +> Anonymous says: +> +> Sure, but it doesn’t feature this optimization. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffolk-dancing-and-general-updates.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/fonts-revisited.md b/docs/website/content/blog/fonts-revisited.md new file mode 100644 index 0000000000..b9b0bec915 --- /dev/null +++ b/docs/website/content/blog/fonts-revisited.md @@ -0,0 +1,70 @@ +--- +title: Fonts Revisited +slug: fonts-revisited +url: /blog/fonts-revisited/ +original_url: https://www.codenameone.com/blog/fonts-revisited.html +aliases: +- /blog/fonts-revisited.html +date: '2012-11-26' +author: Shai Almog +--- + +![Header Image](/blog/fonts-revisited/fonts-revisited-1.png) + + + + +[ +![Picture](/blog/fonts-revisited/fonts-revisited-1.png) +](/img/blog/old_posts/fonts-revisited-large-3.png) + +Fonts are were a painful subject in Codename One, historically devices supported a very limited set of fonts and we were bound by said limitations. However, devices moved forward and finally we too can move forward to more reasonable font support. + +The new font API is limited to Android & iOS, we were considering Blackberry support too but it seems that the font support on Blackberry is too limited for our needs (feel free to correct me if I’m wrong here), on the other platforms a standard system font will be used where fonts aren’t supported. + +In order to use a font just add the ttf file into the src directory, notice that the file must have the “.ttf” extension otherwise the build server won’t be able to recognize the file as a font and set it up accordingly (devices need fonts to be defined in very specific ways). Once you do that you can use the font from code or from the theme. + +In the theme section of the Codename One designer you now have the option to define the font like this: + +* * * + + + + +[ +![Picture](/blog/fonts-revisited/fonts-revisited-2.png) +](/img/blog/old_posts/fonts-revisited-large-4.png) + +The system font will be used where True Type fonts aren’t supported, the size of the font can be one of 5 options. + +Small, medium & large correspond to the 3 system font sizes and occupy the exact same sizes of the system fonts. + +Millimeters & pixels will size the fonts appropriately using the numeric field. + +To use fonts from code just use: + +if(Font.isTrueTypeFileSupported()) { + +Font myFont = Font.createTrueTypeFont(fontName, fontFileName); + +myFont = myFont.derive(sizeInPixels, Font.STYLE_PLAIN); + +// do something with the font + +} + +Notice that in code only pixel sizes are supported so its up to you to decide how to convert that. You also need to derive the font with the proper size unless you want a 0 sized font which probably isn’t very useful. + +The font name is the difficult bit, iOS requires the name of the font which doesn’t always correlate to the file name in order to load the font, its sometimes viewable within a font viewer but isn’t always intuitive so be sure to test that on the device to make sure you got it right. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/full-stack-java-bootcamp.md b/docs/website/content/blog/full-stack-java-bootcamp.md new file mode 100644 index 0000000000..e3c6874db2 --- /dev/null +++ b/docs/website/content/blog/full-stack-java-bootcamp.md @@ -0,0 +1,195 @@ +--- +title: Full Stack Java Bootcamp +slug: full-stack-java-bootcamp +url: /blog/full-stack-java-bootcamp/ +original_url: https://www.codenameone.com/blog/full-stack-java-bootcamp.html +aliases: +- /blog/full-stack-java-bootcamp.html +date: '2017-02-28' +author: Shai Almog +--- + +![Header Image](/blog/full-stack-java-bootcamp/full-stack-java-bootcamp.jpg) + +__ | It’s LIVE! Check out the bootcamp signup [here](https://codenameone.teachable.com/p/full-stack-java-mobile-app-bootcamp/). +---|--- + +Thanks again to everyone who answered my questions. I got tons of valuable feedback on our work & what you would like to learn. It was super helpful and I’m grateful to all of you as you are literally shaping how this bootcamp (and the future of Codename One). I’m sorry if I was brief in some of the thank you emails, it took some time as I wrote them all personally and worked well into the night the other day. + +One of the main things I got from pretty much everyone who wrote is the desire to improve your UI, this is a huge deal for us as I think we have an advantage here. E.g. a lot of developers who wrote to me (some of which worked with us for **years**) weren’t familiar with these demos I’ve published: + + * [Material Screens](https://www.codenameone.com/blog/template-mobile-material-screens-ui-kit.html) + + * [Phoenix](https://www.codenameone.com/blog/template-phoenix-ui.html) + + * [PSD to App](https://www.codenameone.com/blog/psd-to-app-revisited.html) + + * [Clean Modern](http://www.codenameone.com/blog/template-clean-modern-ui-kit.html) + +![This took me a day or two to build \(based on existing design\)](/blog/full-stack-java-bootcamp/Mobile-Material-UI-Screens.png) + +Figure 1. This took me a day or two to build (based on existing design) + +To me these demos show more than just a good looking UI. They hint of the potential…​ + +In the right hands you can produce any damn UI design that your insane designer can come up with. This isn’t true for most other tools as they don’t control every pixel on the screen…​ + +We don’t have that level of control even in regular native apps where an OS update (or vendor customization) can wreck havoc in your meticulously crafted UI. + +Learning to do this in a portable and consistent way is challenging. Some of that is because of the rough edges of our tools & some of that is because of outdated docs/videos. I spend almost all of my time writing documentation, answering your questions on stackoverflow/elsewhere but this is clearly not enough. + +Our open source community is hugely helpful but it isn’t as effective for things like high quality guides. Docs are probably the hardest things to build using a community process. + +### How do we Fix This? + +This will require some work…​ + +When I was a young programmer in my late teens and early 20s I already knew quite a lot but I also had bad habits…​ + +I picked a lot of bad practices from learning on my own and I might have ended up very differently had I not stumbled into amazing mentors who guided me in the right direction. These great mentors transformed the way I code communicate & think. They were pivotal in my career. + +When we started the LWUIT project at Sun Microsystems we spent a lot of with customers trying to understand the difficulties they were addressing firsthand. At that point I realized that not only was I mentoring the junior developers I was working with, I was getting a lot in return. I was able to glimpse into LWUIT thru a fresh pair of eyes and see what we got right and what we got wrong. This improved LWUIT immensely. + +That’s why I spend almost all my time doing customer support, it teaches me a lot and allows me to run the company in a way that makes sense for this type of product. But that’s not enough…​ + +### Bootcamp + +A bootcamp isn’t a regular course. It runs over a narrow stretch of time & is deeply interlaced with personal 1 on 1 mentoring. This means I’ll need to seriously clear my schedule to do this but I think the value proposition is **huge**. Unfortunately it also means this doesn’t scale all too well either. Here I want to provide from my experience but also learn from yours so I can initiate changes and we can adapt better to fit your needs. + +The core focus of the bootcamp would be on building a compelling UI that would be native in feel and quality without compromising on anything. The samples I gave you above are great but they’re just samples. When you need to take an app all the way from generating a certificate, designing a gorgeous UI, building a server, connecting it and putting it into production in the store this becomes a challenge with many pitfalls along the way. + +But this is not enough, I want an end to end full stack application from mobile to server. This is important because so many developers today carry the full weight of responsibility to build a complete app including the server side, networking and everything. + +### Building an App from Scratch to Production + +When I told Chen about my plan to do a 4 week bootcamp and build a full production app as part of it he had his doubts. I’m paraphrasing here but this is the gist of what he said: “you don’t really think you can build a full production grade app in 4 weeks?”. + +My answer was: “no, I will build the app and server in two weeks!” + +That’s ambitious but that’s exactly what a bootcamp is, it’s a startup for all intents and purposes. Building a full fledged well designed and architected app is something all of you can do within 2-4 weeks when using Java/Codename One. + +The two additional weeks will cover a lot of things and include personal mentoring which I think is crucial for our shared success. + +### More Details Coming Soon + +There is so much more I would like to cover and I’ll cover some of the nitty gritty details on how this bootcamp will achieve it’s transformative goals in my post early next week. There are many logistic details that we need to sort out mostly with the company as I will find it hard to handle my day to day tasks during the bootcamp. + +In the meantime, if you haven’t answered my email please do so as I’m still interested in hearing more. Also feel free to write and comment in the blog with thoughts/issues/concerns etc. + +I’d also appreciate sharing this with your friends & co-workers who might be appropriate. + +This was the first article in a 3 part series, check out part 2 [here](/blog/spring-template-more-about-bootcamp.html). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Dalvik** — March 1, 2017 at 1:04 pm ([permalink](https://www.codenameone.com/blog/full-stack-java-bootcamp.html#comment-23028)) + +> Interesting stuff, is this for all levels? +> Is there a place to register? +> How would this be structured? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffull-stack-java-bootcamp.html) + + +### **Shai Almog** — March 1, 2017 at 3:34 pm ([permalink](https://www.codenameone.com/blog/full-stack-java-bootcamp.html#comment-23038)) + +> Shai Almog says: +> +> Java knowledge is a must, ideally some level of Codename One experience would help but there will be optional content at the start that a person completely new to Codename One would be able to follow to get started quickly. +> +> I’ll answer the rest in an upcoming post. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffull-stack-java-bootcamp.html) + + +### **Dalvik** — March 2, 2017 at 8:45 am ([permalink](https://www.codenameone.com/blog/full-stack-java-bootcamp.html#comment-21565)) + +> Dalvik says: +> +> Thanks! Looking forward to it! +> +> Will this be at a physical location or will I be able to join online? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffull-stack-java-bootcamp.html) + + +### **Ignatus Ujomor** — March 2, 2017 at 9:05 am ([permalink](https://www.codenameone.com/blog/full-stack-java-bootcamp.html#comment-23320)) + +> Ignatus Ujomor says: +> +> I am interested in the bootcamp and want to know the date, location, cost (if any), and other requirements. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffull-stack-java-bootcamp.html) + + +### **Chad Elofson** — March 2, 2017 at 9:21 am ([permalink](https://www.codenameone.com/blog/full-stack-java-bootcamp.html#comment-23397)) + +> Chad Elofson says: +> +> This sounds great. I have gained insight from Steve Hannah already. So, I feel this would be great to take my Codename One experience to the next level. +> +> Looking forward to it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffull-stack-java-bootcamp.html) + + +### **Shai Almog** — March 2, 2017 at 10:02 am ([permalink](https://www.codenameone.com/blog/full-stack-java-bootcamp.html#comment-23238)) + +> Shai Almog says: +> +> Great! +> I’ll announce all the details in the blog since the final dates aren’t settled (a lot of logistics around my time). Registration should open soon though. +> +> The bootcamp will be over the internet with 1 on 1 sessions going over skype or something like that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffull-stack-java-bootcamp.html) + + +### **Shai Almog** — March 2, 2017 at 10:03 am ([permalink](https://www.codenameone.com/blog/full-stack-java-bootcamp.html#comment-23078)) + +> Shai Almog says: +> +> Great. This will be over the internet thru skype or similar tools for the 1 on 1. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffull-stack-java-bootcamp.html) + + +### **Shai Almog** — March 2, 2017 at 10:04 am ([permalink](https://www.codenameone.com/blog/full-stack-java-bootcamp.html#comment-23328)) + +> Shai Almog says: +> +> Thanks, I’m sure Steve is thrilled to hear that 😉 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffull-stack-java-bootcamp.html) + + +### **salah Alhaddabi** — March 2, 2017 at 3:04 pm ([permalink](https://www.codenameone.com/blog/full-stack-java-bootcamp.html#comment-23269)) + +> salah Alhaddabi says: +> +> Dear Shai very excellent idea. Would be great if you can cover backend stuff using java ee 7 api only without third party libraries. You can for example include rest api, websocket, jms, jason processing, cdi, jpa, ejb and then present how to call web services layer from CN1 and also how to asynchrounously listen to websockets and best practices to update UI and to upliad/download images so everything is in java +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffull-stack-java-bootcamp.html) + + +### **Shai Almog** — March 2, 2017 at 3:33 pm ([permalink](https://www.codenameone.com/blog/full-stack-java-bootcamp.html#comment-23183)) + +> Shai Almog says: +> +> Thanks for the feedback. I’m somewhat conflicted between simple tomcat, Java EE or Spring in terms of backend. My goal is to spend as little time as possible configuring stuff and make the solution as simple as possible so people can adapt this easily to their “real world” setups. +> +> I don’t want to use something too exotic though, so I won’t go into some of the newer microservice style frameworks. My main focus by a huge margin is on the client, there are great Java EE/Spring etc. courses out there and I don’t think I can improve on them. What I want to do is show how all this ties together to a single cohesive product. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffull-stack-java-bootcamp.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/further-refined-cross-platform-mobile-gui-builder.md b/docs/website/content/blog/further-refined-cross-platform-mobile-gui-builder.md new file mode 100644 index 0000000000..1b28dbfa51 --- /dev/null +++ b/docs/website/content/blog/further-refined-cross-platform-mobile-gui-builder.md @@ -0,0 +1,194 @@ +--- +title: Further Refined Cross Platform Mobile GUI Builder +slug: further-refined-cross-platform-mobile-gui-builder +url: /blog/further-refined-cross-platform-mobile-gui-builder/ +original_url: https://www.codenameone.com/blog/further-refined-cross-platform-mobile-gui-builder.html +aliases: +- /blog/further-refined-cross-platform-mobile-gui-builder.html +date: '2016-10-04' +author: Shai Almog +--- + +![Header Image](/blog/further-refined-cross-platform-mobile-gui-builder/new-gui-builder.jpg) + +Chen has been working quite a bit on the new GUI Builder and made some significant changes both to it’s look and +functionality. These changes are wide reaching covering the appearance, functionality and stability of the GUI Builder. + +![Starting page after recent changes see if you can spot them all...](/blog/further-refined-cross-platform-mobile-gui-builder/new-ux-for-gui-builder.png) + +Figure 1. Starting page after recent changes see if you can spot them all…​ + +### Palette Relocation + +The component palette is using an accordion now and was relocated to the right side of the UI. It is also available +as a popup below the tree…​ + +If you select a node in the tree and press the `+` sign below the tree you will see the palette entries and you can click +one of them to add it into the given node as such: + +![New popup palette UI](/blog/further-refined-cross-platform-mobile-gui-builder/new-ux-for-gui-builder-palette-popup.png) + +Figure 2. New popup palette UI + +### Up/Down Move + +Entries in the tree can now be moved up/down the tree even between container boundaries. +You can do this by selecting an entry and pressing the up arrow `^` or similar down arrow next to it below the tree. + +This is useful for simple reordering without drag and drop. Ideally we wanted to enable drag & drop in the tree but +this collides with the scrolling functionality to some degree so we took the lazy approach. + +### Material Icons Support + +You can now pick a material design icon directly from the designer. When you click any icon property you will +see this dialog + +![Pick material icon or image from the resource file](/blog/further-refined-cross-platform-mobile-gui-builder/new-ux-for-gui-builder-image-pick.png) + +Figure 3. Pick material icon or image from the resource file + +If you choose to pick an image from the material design icon font you will be presented with a dialog like this +coupled with a search field: + +![List of material design icons](/blog/further-refined-cross-platform-mobile-gui-builder/new-ux-for-gui-builder-pick-material.png) + +Figure 4. List of material design icons + +### Missing In Action + +As part of these changes we removed a couple of features, let us know if they matter to you. + + * **Multi Select** – This was a very powerful feature that allowed editing multiple entries at once & enclosing them +in a parent `Container`. It had confusing usage and a few lingering bugs + + * **Palette Search** – When migrating the palette from a Container to an Accordion search was removed. I personally +liked that search a lot and used it quite a bit as I prefer typing + +We have internal debates on whether these features are “really” needed/used. If you used them and want them +back let us know! + +### Moving Forward + +We hope to release a plugin update this coming Friday which will include all of these changes…​ + +Where do we go from here is very much up to you! + +We need your bug reports, suggestions and requests to tune the designer to match your workflow. Naturally we +can’t entertain every request/suggestion but we try to listen and base our work on your needs. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **disqus** — October 12, 2016 at 4:14 pm ([permalink](https://www.codenameone.com/blog/further-refined-cross-platform-mobile-gui-builder.html#comment-22874)) + +> Updated netbeans plugin to Version: 3.5.5. Post update GUI Builder button events not functional after update. On looking at the generated code found this +> public void actionPerformed(com.codename1.ui.events.ActionEvent ev) { +> com.codename1.ui.Component sourceComponent = ev.getComponent(); +> if(sourceComponent.getParent().getLeadParent() != null) { +> sourceComponent = sourceComponent.getParent().getLeadParent(); +> } +> +> if(sourceComponent == gui_Button) { +> } +> } +> +> which should be +> if(sourceComponent == gui_Button) { +> onButtonActionEvent(ev); +> } +> +> Kindly fix the problem and let me know how can I do a dirty fix till then because this is generated code and gets overwritten everytime. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffurther-refined-cross-platform-mobile-gui-builder.html) + + +### **Chen Fishbein** — October 12, 2016 at 6:33 pm ([permalink](https://www.codenameone.com/blog/further-refined-cross-platform-mobile-gui-builder.html#comment-23051)) + +> Thanks, it will be fixed for the next update. +> In the meantime you can just add an ActionListener to your Button right after the call to initGuiBuilderComponents +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffurther-refined-cross-platform-mobile-gui-builder.html) + + +### **Chidiebere Okwudire** — November 1, 2016 at 10:02 am ([permalink](https://www.codenameone.com/blog/further-refined-cross-platform-mobile-gui-builder.html#comment-23157)) + +> How does the new GUI builder paradigm work with (UI) inheritance? +> +> Use case: Several forms share a lot in common (custom header/footer/common body layout). As such I would like to have a base form and in subsequent forms, include the form content in my custom body layout. A quick look didn’t reveal any obvious way to achieve this without overriding the Form.addComponent() methods…. Please share your thoughts on how this can best be realized +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffurther-refined-cross-platform-mobile-gui-builder.html) + + +### **Shai Almog** — November 1, 2016 at 10:17 am ([permalink](https://www.codenameone.com/blog/further-refined-cross-platform-mobile-gui-builder.html#comment-22974)) + +> We did just that in the new Phoenix demo, all forms derive from a common base form for the common side menu. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffurther-refined-cross-platform-mobile-gui-builder.html) + + +### **Chidiebere Okwudire** — November 1, 2016 at 11:00 am ([permalink](https://www.codenameone.com/blog/further-refined-cross-platform-mobile-gui-builder.html#comment-23173)) + +> Chidiebere Okwudire says: +> +> Perfect timing. I’ll have a look! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffurther-refined-cross-platform-mobile-gui-builder.html) + + +### **disqus** — November 5, 2016 at 8:59 pm ([permalink](https://www.codenameone.com/blog/further-refined-cross-platform-mobile-gui-builder.html#comment-21506)) + +> disqus says: +> +> working in the new version of the plugin 3.5.7 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffurther-refined-cross-platform-mobile-gui-builder.html) + + +### **Shai Almog** — November 6, 2016 at 4:23 am ([permalink](https://www.codenameone.com/blog/further-refined-cross-platform-mobile-gui-builder.html#comment-23194)) + +> Shai Almog says: +> +> Right click the project. Select properties and click OK in the properties dialog. Try running the project again. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffurther-refined-cross-platform-mobile-gui-builder.html) + + +### **Francesco Galgani** — June 16, 2017 at 1:30 pm ([permalink](https://www.codenameone.com/blog/further-refined-cross-platform-mobile-gui-builder.html#comment-23514)) + +> Francesco Galgani says: +> +> I recently found this old blog post, that clarify why I didn’t find the “Multi Select” feature that is indicated in the developer guide (that should be updated). +> I think that is very important to be able to put some components in a container easily (and viceversa, that is put some components out of their container). +> The actual New Gui Builder has a lot of issues: if you change a value in the properties (like a component name), the tree is not updated; if I add two buttons and a container, I cannot drag and drop the buttons in the container (I can use move up/down buttons, but they are not convenient if I have a lot of components); if I select a container in tree and click on Cut, that container is still shown (the tree is not updated); if I select again that container and I click on Cut, I get the error “No component is selected”; if I cut and paste a component, its name will be changed; if I set a nested container as BorderLayout and then I click in tree to a button inside it, the box below the tree remain as it is, showing the layout of the container instead of properties of the button; I exerienced that in the preview some components are missing, but they are shown clicking on the Preview Design icon; if I set a container with a Table layout, in the settings I can set rows and columns only, I cannot customize every cell like in an html table; etc., maybe I did not understand how to use Gui Builder, but in my opinion it’s buggy and difficult to use. I’m waiting for a new version of the Gui Builder, thank you for your effort to make it better 🙂 +> +> There is also a small bug both in the Gui Builder and in the Codename One Designer: some menu items are not shown when I click on the menu. For example, in the Gui Builder if I click on “File” I’ll see the underlying commands (Save, Exit), but if I move the mouse cursor to “Edit” or “Help” no commands underlying Edit or Help are shown (to get them, I have to click again on Edit or Help). In the Codename One Designer, the issue is a bit different: for example, I click on the menu voice “Codename One”, I see: Signup, Login, a blank space, Advanced. To see the “Live preview” item istead of the blank space (and other missing items replaced by blank spaces), I have to set the Look&Feel as cross-platform every time that I open the Designer (however I prefer the System Look&Feel). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffurther-refined-cross-platform-mobile-gui-builder.html) + + +### **Shai Almog** — June 17, 2017 at 7:08 am ([permalink](https://www.codenameone.com/blog/further-refined-cross-platform-mobile-gui-builder.html#comment-23413)) + +> Shai Almog says: +> +> Thanks for this feedback! +> +> We have a big update for the GUI builder coming soon, I hope it will make it into 3.7. If so it will change everything about the GUI builder in a big way… +> +> The problem with documenting something like this that evolves so quickly is that I just can’t keep up. If I will do a screencast or new screenshots now they will be wrong by July. +> +> We do need these issue reports but the comment system is a great place to lose such feedback. I would suggest filing issues in the issue tracker here: [http://github.com/codenameo…]() +> +> Also include screenshots with the issues as some of these things I don’t follow like the voice menu which isn’t something that’s a part of our app. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ffurther-refined-cross-platform-mobile-gui-builder.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/gallery-icon-update.md b/docs/website/content/blog/gallery-icon-update.md new file mode 100644 index 0000000000..b231d850df --- /dev/null +++ b/docs/website/content/blog/gallery-icon-update.md @@ -0,0 +1,55 @@ +--- +title: Gallery, Icons & Updates +slug: gallery-icon-update +url: /blog/gallery-icon-update/ +original_url: https://www.codenameone.com/blog/gallery-icon-update.html +aliases: +- /blog/gallery-icon-update.html +date: '2015-03-17' +author: Shai Almog +--- + +![Header Image](/blog/gallery-icon-update/gallery-chart-fonts-icon.png) + +Now that the new website is live we are down to standard business again beyond just the typical bug fixes. Chen just updated the gallery support to include the ability to pick a video file and not just an image file. +The default functionality remains the same and compatible but now you can do something like: + + + Display.getInstance().openGallery(new ActionListener() { + public void actionPerformed(ActionEvent ev) { + if(ev != null && ev.getSource() != null) { + String filePathToGalleryImageOrVideo = (String)ev.getSource(); + .... + } + } + }, Display.GALLERY_ALL); + +You can now use GALLERY_ALL, GALLERY_VIDEO or GALLERY_IMAGE to pick either one or both when showing +the gallery UI. + +A rather interesting issue was opened last week where a developer got a reject from Apple’s upload tool +due to an invalid binary. Missing the Icon.png file… +Our iOS project build is pretty complex e.g. +[it takes screenshots](http://www.codenameone.com/blog/the-7-screenshots-of-ios) +and it also handles things like icon resizing. The latter is much simpler, we generate the roughly 10 icon +sizes the Apple needs for the various iOS devices from the one icon you supply (seriously they expect 10 icons…). + +We store these icons in the bundle and in this case the developer also stored an icon.png file in the root triggering +a collision. Naturally our build process needs to be smarter and catch onto those things but I would recommend +that you also practice caution when placing files in the root and try to place as much as possible within res files +(yes you can have more than one) especially because they let you take advantage of multi-images. + +#### Quick note about the github migration plans + +We haven’t started yet since we need to cleanup a lot of things first. We also need to start updating the +plugins and everything involved to the new URL’s. Once everything is planned out we will start a migration, +hopefully issues will be able to make the transition. +We hope to publish a detailed transition plan sometime in the next couple of weeks. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/game-of-code.md b/docs/website/content/blog/game-of-code.md new file mode 100644 index 0000000000..745e1ea779 --- /dev/null +++ b/docs/website/content/blog/game-of-code.md @@ -0,0 +1,71 @@ +--- +title: Game Of Code +slug: game-of-code +url: /blog/game-of-code/ +original_url: https://www.codenameone.com/blog/game-of-code.html +aliases: +- /blog/game-of-code.html +date: '2014-08-16' +author: Shai Almog +--- + +![Header Image](/blog/game-of-code/game-of-code-1.png) + + + + + + + +![Picture](/blog/game-of-code/game-of-code-1.png) + + + + +[ +JavaZone +](http://2014.javazone.no/) +just released their traditional annual clip which is especially amusing for fans of the Song Of Ice & Fire series (or the Game Of Thrones TV adaptation). If you haven’t seen the clips from these guys before you MUST check them out +[ +here +](https://www.youtube.com/channel/UC1s3pFsMZv37NAxIIW90MGw) +, including spoofs of house of cards and breaking bad (not to mention years of hilarious clips)! + +Very cool. + +We are hard at work for my workshop at JavaZone which will teach the creation of a Codename One application from start to finish, if you haven’t signed up you should. JavaZone is one of the best produced conference I’ve attended and its loads of fun with great humor, music, food and alcohol. Definitely worth the trip. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — August 19, 2014 at 5:19 pm ([permalink](https://www.codenameone.com/blog/game-of-code.html#comment-22098)) + +> Anonymous says: +> +> Hey Shai, can you please post the link to sign up for the CN1 workshop? thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgame-of-code.html) + + +### **Anonymous** — August 20, 2014 at 2:34 am ([permalink](https://www.codenameone.com/blog/game-of-code.html#comment-21593)) + +> Anonymous says: +> +> That’s the session [http://2014.javazone.no/pre…]() its in JavaZone in Oslo. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgame-of-code.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/game-on.md b/docs/website/content/blog/game-on.md new file mode 100644 index 0000000000..5393826a4b --- /dev/null +++ b/docs/website/content/blog/game-on.md @@ -0,0 +1,60 @@ +--- +title: Game On +slug: game-on +url: /blog/game-on/ +original_url: https://www.codenameone.com/blog/game-on.html +aliases: +- /blog/game-on.html +date: '2015-01-06' +author: Shai Almog +--- + +![Header Image](/blog/game-on/game-on-1.png) + + + + + +![Picture](/blog/game-on/game-on-1.png) + + + + + + + + + + +A Codename One community member +[ +Antonio Mannucci offered +](https://groups.google.com/d/msg/codenameone-discussions/wumShzMwUmw/1JAFcEanABAJ) +to release a gaming API that he created a while back. It took him some time but he finally delivered on his promise by +[ +releasing a cn1lib for simple 2D games in Codename One +](https://code.google.com/p/core2d-cn1lib/) +and a demo game to go with it. + +The project is still pretty rough in the sense that there is no real documentation or getting started guide. However, there isn’t much that needs saying… Just checkout the code and build the library then run the example demo. The demo has some issues that I’m unclear about but it looks promising. + +The basic concepts of Sprites, tiles, touch keypad, music & sound effects all seem to be in place. I’m not sure where this is going since gaming isn’t in our core focus, but if you are interested in building a game using Codename One then looking/contributing to this project might be interesting. + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/garbage.md b/docs/website/content/blog/garbage.md new file mode 100644 index 0000000000..fb3061dacb --- /dev/null +++ b/docs/website/content/blog/garbage.md @@ -0,0 +1,53 @@ +--- +title: Garbage Collection +slug: garbage +url: /blog/garbage/ +original_url: https://www.codenameone.com/blog/garbage.html +aliases: +- /blog/garbage.html +date: '2014-06-25' +author: Shai Almog +--- + +![Header Image](/blog/garbage/garbage-1.png) + + + + + +![Picture](/blog/garbage/garbage-1.png) + + + + +We’ve been spending an excessive amount of time tuning our garbage collection and memory management of the new iOS VM based on profiler output. This is one of the cool features in the approach we took (translating Java to C rather than going directly to machine code), we can use Apple’s nifty profiling tools to see where the CPU/GPU spend their time. + +After quite a few profiling sessions it became apparent that the GC is the main reason for the performance overhead. Further digging showed that mutexes were the real issue here. + +Our GC is non-blocking and concurrent which means it runs in a separate thread and never stops the world during collection. However, in order to track all the memory we use a wrapper around malloc which has to be threadsafe and stores all the objects allocated. This allows our memory sweep algorithm to remove all objects that are no longer used, the problem is that access to this global pool must be synchronized… + +To solve this problem we rethought the basic concept behind this, now the pool is managed by a single thread that stores/removes elements. Every thread has a set of objects that it allocated since the last GC and every time a GC runs it copies the newly created objects to the global sweep pool and wipes the slate. This effectively removes all synchronization from the very expensive allocation process which is pretty cool. + +On a separate subject our Codename One workshop for +[ +JavaZone +](http://2014.javazone.no/) +just got accepted, that is pretty cool! + +I really +[ +enjoyed JavaZone last year +](http://www.codenameone.com/3/post/2013/09/javazone-trip-report.html) +and felt it exceeded JavaOne in many aspects. This would actually be a workshop session where you can learn Codename One programming from me in person, it would be great seeing Codename One developers there. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/gc-crashes-bugs.md b/docs/website/content/blog/gc-crashes-bugs.md new file mode 100644 index 0000000000..403f253c3f --- /dev/null +++ b/docs/website/content/blog/gc-crashes-bugs.md @@ -0,0 +1,77 @@ +--- +title: GC Crashes & Bugs +slug: gc-crashes-bugs +url: /blog/gc-crashes-bugs/ +original_url: https://www.codenameone.com/blog/gc-crashes-bugs.html +aliases: +- /blog/gc-crashes-bugs.html +date: '2015-03-30' +author: Shai Almog +--- + +![Header Image](/blog/gc-crashes-bugs/hqdefault.jpg) + +As part of tracking a bug in iOS media playback Steve hit upon some code that recreated the OpenGL framebuffer +pretty much all the time. This was there to allow device rotation to work, but was implemented incorrectly… +After this fix animations and UI is much smoother on iOS, if you notice any potential issues let us know. + +In other news we just fixed two big GC issues in the new VM. The first was a rather complex edge case with GC firing +up during native code where more than one allocation was made during the second (or later) allocations +(yes edge case). Since objects allocated in native code still don’t have hard Java references the GC can’t “see” +those references and thus wiped them. The solution was pretty simple, we now toggle a flag that essentially +blocks GC from happening while we are in such a native method… + +The other issue was arguably harder to catch since it was more conceptual, but the fix consisted of exactly two +lines of code… As you recall we use a mark-sweep algorithm to clean up the objects, new objects were implicitly +created as marked which seemed to make a lot of sense (we create an object we will probably need it!). +However, this created a rather tricky situation… If a user creates a new array e.g.: + + + List objectsInListThatArentYetMarked = ...; + Object[] newArrayToContainObjects = new Object[objectsInListThatArentYetMarked.size()]; + objectsInListThatArentYetMarked.toArray(newArrayToContainObjects); + objectsInListThatArentYetMarked = null; + + +In this case objectsInListThatArentYetMarked will get wiped by the GC since its no longer necessary and won’t +be marked. Since the array is newly created it will be marked, so when our mark algorithm reaches it then it will +see a marked object and won’t traverse further (otherwise we will get into infinite recursions and performance penalties). +The solution is actually quite simple, we give newly created objects a special case -1 value and so they will +be marked as usual, but won’t be GC’d. + +Steve also made some fixes for premature object deletion, e.g. if we invoke a native method in C which uses +iOS’s dispatch_async calls (their equivalent of the callSerially method). By the time the async block is reached +the String argument might have been GC’d. However, there is a special case for releasing the NSString asynchronously +just to avoid that. Steve made sure we don’t try to access Java objects that might be GC’d anywhere in our code. + +### Update On JavaScript VM + +Steve made some pretty remarkable progress with the JavaScript VM and posted the video below showing +off the unmodified poker demo running in a browser! +For those of you who haven’t followed this, the JavaScript VM port essentially works just like every other Codename One +port where our build servers translate the java bytecode into JavaScript with the right porting layer. +Unlike GWT this port works with threading code, unlike other solutions (such as echo2) this is a purely client +side implementation. This would not have been possible just a couple of years ago but since JavaScript +VM’s have come such a long way its actually proving to be a pretty interesting port. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **shannah78** — April 6, 2015 at 6:07 pm ([permalink](https://www.codenameone.com/blog/gc-crashes-bugs.html#comment-22043)) + +> shannah78 says: +> +> I would like to add that the fundamental advancement that has allowed us to run multithreaded code has nothing to do with the “Javascript VM”. Rather it is that we are using TeaVM to convert to javascript, and it includes a support for threads. This port would not have been possible without TeaVM or without Alexey Andreev’s help (TeaVM’s author). For more about TeaVM, check out [https://github.com/konsolet…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgc-crashes-bugs.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/geo-visualization-library.md b/docs/website/content/blog/geo-visualization-library.md new file mode 100644 index 0000000000..da7ee94f61 --- /dev/null +++ b/docs/website/content/blog/geo-visualization-library.md @@ -0,0 +1,254 @@ +--- +title: Geo-Viz and Codename One +slug: geo-visualization-library +url: /blog/geo-visualization-library/ +original_url: https://www.codenameone.com/blog/geo-visualization-library.html +aliases: +- /blog/geo-visualization-library.html +date: '2015-03-22' +author: Steve Hannah +--- + +![Header Image](/blog/geo-visualization-library/geoviz_demo.png) + +Table of Contents + + * What does the GeoViz Library do? + * What is GeoJSON? + * GeoVizComponent vs MapComponent vs Native Maps + * Key Features + * Basic Usage + * Step One: Load the GeoJSON file + * Step Two: Create the GeoVizComponent + * Implementing a Custom Painter + +I attended a tutorial at OSCON last year on HTML5 graphics where I was introduced to some cool data-visualization technologies. One thing that left an impression was the in [GeoJSON format](http://geojson.org/), which we used to generate some maps inside the browser using the D3 library and SVG. This was around the time that I was working on the new Codename One graphics pipeline, so at each step of the tutorial my inner commentator was whispering “we could do this in Codename One without too much difficulty”. + +Fast forward 6 months, and the new graphics pipeline is complete, so I thought, why not try implementing some of those cool GeoViz features in Codename One. We have all the pieces in place? So I present the [Codename One GeoViz library](https://github.com/shannah/CN1GeoViz). + +## What does the GeoViz Library do? + +The GeoViz library allows you to load geographic data in [GeoJSON format](http://geojson.org/), and render it visually in your app. Below is a map of the USA that was rendered using this library. + +![GeoViz Demo Screenshot](/blog/geo-visualization-library/geoviz_demo.png) + +### What is GeoJSON? + +GeoJSON is a standard format for storing geographic data in JSON format. A GeoJSON file may store a number of “features” which may include shape coordinates as well as information associated with the feature. For example, in the USA Map example, each state is a “feature” that includes shape coordinates for its contour, as well as property information such as the state name. + +One of the nice things about [GeoJSON](http://geojson.org/) is that it is already widely used and there are lots of existing free data sources (e.g. [this GitHub Repo](https://github.com/johan/world.geo.json/tree/master/countries)) where you can obtain state, country, city, etc…​ outlines that can now be easily included in your applications. + +### GeoVizComponent vs MapComponent vs Native Maps + +Codename One already had two mechanisms for displaying maps: the MapComponent and the Native Maps library. Their purpose is different than the GeoVizComponent. Some key differences include: + + 1. The MapComponent uses a “tile”-based approach where it downloads tile images from a map server (e.g. Open Streetmaps or Google Maps). The [GeoVizComponent](https://rawgit.com/shannah/CN1GeoViz/master/dist/javadoc/com/codename1/geoviz/GeoVizComponent.html) renders geographic “shapes” that are stored as vectors so they can be rendered at any size, and transformed in any way you like without pixelization. + + 2. The MapComponent displays only maps as they are provided by the specified Map server. The [GeoVizComponent](https://rawgit.com/shannah/CN1GeoViz/master/dist/javadoc/com/codename1/geoviz/GeoVizComponent.html) will render any geographic information that can be expressed in a GeoJSON file. This might include a map of a building only, or a sparse map that only includes some key landmarks, or anything else you like. + +### Key Features + + * Pan and zoom. The component optionally supports pinch zoom and panning by dragging with your finger. You can also programmatically set the center point and zoom level, and animate the transition to the new viewport settings. + + * Custom painter support. You can implement your own painters to customize how features of the map are rendered. E.g. you can change the background color or different regions based on the data in associated data sets. + + * FeaturePressed/Released Events. You can detect touches to features of the map and respond to them accordingly. + +## Basic Usage + +### Step One: Load the GeoJSON file + + + GeoJSONLoader loader = new GeoJSONLoader(); + FeatureCollection coll = loader.loadJSON( + Display.getInstance().getResourceAsStream(null, "/us-states.json"), + "UTF-8" + ); + +This example loads the us-states JSON file from the app resources using the [GeoJSONLoader](https://rawgit.com/shannah/CN1GeoViz/master/dist/javadoc/com/codename1/geoviz/GeoJSONLoader.html) class. + +### Step Two: Create the GeoVizComponent + + + GeoVizComponent comp = new GeoVizComponent(coll); + +### Implementing a Custom Painter + +The default painter will just render the map with black outlines and white fills. If you want to customize this you can install your own custom [FeaturePainter](https://rawgit.com/shannah/CN1GeoViz/master/dist/javadoc/com/codename1/geoviz/FeaturePainter.html). The following is an example custom painter taken from the [GeoViz demo](https://github.com/shannah/GeoVizDemo): + + + // Add a custom feature painter so that we can paint states different + // colors depending on the data in our CSV file. + comp.setFeaturePainter(new FeaturePainter(){ + + /** + * Callback to fill a feature (State). We implement this + * so that we can fill selected states with red and other states + * a color based on the currently selected year. + * @param g The graphics context + * @param feature The feature to paint + * @param path The shape that is to be filled. + */ + @Override + protected void fill(Graphics g, Feature feature, GeneralPath path) { + + int oldColor = this.getFillColor(); + int oldAlpha = this.getFillAlpha(); + if (feature == selectedFeature){ + this.setFillColor(0xff0000); + } else { + RegionData[] regionData = popData.getRegionData( + (String)feature.getProperties().get("name") + ); + if (currentYear > 0){ + if (mode==MODE_POPULATION){ + for (RegionData d : regionData){ + if (d.year == currentYear){ + if (d.pop != 0){ + this.setFillColor( + getColor(1.0, 0, 0, d.pop, minPopulation, maxPopulation)); + this.setFillAlpha(getAlpha(d.pop, minPopulation, maxPopulation)); + } + break; + } + } + } else if (mode==MODE_DENSITY){ + for (RegionData d : regionData){ + if (d.year == currentYear){ + if (d.density != 0){ + this.setFillColor(getColor(0, 1.0, 0, d.density, minDensity, maxDensity)); + this.setFillAlpha(getAlpha(d.density, minDensity, maxDensity)); + } + break; + } + } + } + } + } + super.fill(g, feature, path); + this.setFillColor(oldColor); + this.setFillAlpha(oldAlpha); + } + + }); + +For the full example, check out the [GeoViz Demo](https://github.com/shannah/GeoVizDemo). + +You can also check out the Javadocs for the the library [here](https://rawgit.com/shannah/CN1GeoViz/master/dist/javadoc/index.html). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **ftp27** — March 25, 2015 at 10:27 am ([permalink](https://www.codenameone.com/blog/geo-visualization-library.html#comment-24242)) + +> Yesterday I’m solved a similar task 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgeo-visualization-library.html) + + +### **Chidiebere Okwudire** — March 18, 2017 at 11:57 pm ([permalink](https://www.codenameone.com/blog/geo-visualization-library.html#comment-23408)) + +> Chidiebere Okwudire says: +> +> Hi, nice! I want to do something but I’m wondering how best to convert my map (in this case an office floor map) into GeoJSON so that users can click on specific, predefined areas to designate their office spaces. Any pointers? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgeo-visualization-library.html) + + +### **Chidiebere Okwudire** — March 19, 2017 at 12:05 am ([permalink](https://www.codenameone.com/blog/geo-visualization-library.html#comment-23420)) + +> Chidiebere Okwudire says: +> +> @Steve: Demo link still points to the now extinct googlecode repo. Can you update it to point to Github? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgeo-visualization-library.html) + + +### **Shai Almog** — March 19, 2017 at 5:12 am ([permalink](https://www.codenameone.com/blog/geo-visualization-library.html#comment-23426)) + +> Shai Almog says: +> +> We moved the demo repo here: [https://github.com/codename…]() +> We probably need to refresh that demo +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgeo-visualization-library.html) + + +### **Chidiebere Okwudire** — March 25, 2017 at 10:30 pm ([permalink](https://www.codenameone.com/blog/geo-visualization-library.html#comment-23247)) + +> Chidiebere Okwudire says: +> +> Any idea if/how I can apply this concept to an arbitrary image? Use case is a floor map in which I want to define sitting positions such that users can click and indicate where they’re sitting for example. User ‘ftp27’ seems to have done something similar but I don’t know how… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgeo-visualization-library.html) + + +### **shannah78** — March 31, 2017 at 1:26 pm ([permalink](https://www.codenameone.com/blog/geo-visualization-library.html#comment-23481)) + +> shannah78 says: +> +> I’m not sure the best way to do this. It depends on what data you already have about your floor plan. E.g. Do you have the lat/lng coordinates of all office spaces? How big is the floor plan? If you don’t have the coordinates, it might be just as easy to create some sort of “hot” map to make certain areas clickable. There might be specific tools for doing a job like this, but in the worst case, I might just open my floor plan in photoshop, then create a new layer for each clickable office space and draw a rectangle of some sort on that layer over the corresponding office space. You could probably then export the layers in a way that you could feed into your app. +> +> I’ve never had to perform this task though so there may be better ways. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgeo-visualization-library.html) + + +### **Chidiebere Okwudire** — April 2, 2017 at 3:28 pm ([permalink](https://www.codenameone.com/blog/geo-visualization-library.html#comment-23490)) + +> Chidiebere Okwudire says: +> +> All I have is a high-res jpeg. I’ve read a bit more about GeoViz and it indeed appears to be for geospatial data and not arbitrary images. +> +> It’s pretty easy for me to determine the pixels coordinates of the polygons bounding the desired spaces. However, given the different DPIs on various devices, I doubt this will work… What coordinates are provided in the pointerPressed(), pointerReleased() methods of the ImageViewer class? I’m wondering if I can map these in a DPI-independent way… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgeo-visualization-library.html) + + +### **Shai Almog** — April 2, 2017 at 5:03 pm ([permalink](https://www.codenameone.com/blog/geo-visualization-library.html#comment-23363)) + +> Shai Almog says: +> +> You can just scale both images together and use getRGB to get the pixel data of the color map. +> +> You could use ImageViewer or just do something similar, check out its code. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgeo-visualization-library.html) + + +### **Chidiebere Okwudire** — April 5, 2017 at 3:05 am ([permalink](https://www.codenameone.com/blog/geo-visualization-library.html#comment-23371)) + +> Chidiebere Okwudire says: +> +> I’m not sure I completely get it: How does getRGB help in this case? On the original image, I define the coordinates of the bounding boxes of areas of interest. My challenge is how to translate these to the scaled image regardless of device DPI such that I can detect clicks within those areas and do other things like draw overlays. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgeo-visualization-library.html) + + +### **Shai Almog** — April 5, 2017 at 4:32 am ([permalink](https://www.codenameone.com/blog/geo-visualization-library.html#comment-23315)) + +> Shai Almog says: +> +> I don’t see the problem. You can just draw the image in any resolution you want. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgeo-visualization-library.html) + + +### **Chidiebere Okwudire** — April 5, 2017 at 5:41 am ([permalink](https://www.codenameone.com/blog/geo-visualization-library.html#comment-23381)) + +> Chidiebere Okwudire says: +> +> Okay. I’ll try it out and let you know if I run into any difficulties 😉 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgeo-visualization-library.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/getting-ready-for-11.md b/docs/website/content/blog/getting-ready-for-11.md new file mode 100644 index 0000000000..00c2db882d --- /dev/null +++ b/docs/website/content/blog/getting-ready-for-11.md @@ -0,0 +1,77 @@ +--- +title: Getting Ready For 1.1 +slug: getting-ready-for-11 +url: /blog/getting-ready-for-11/ +original_url: https://www.codenameone.com/blog/getting-ready-for-11.html +aliases: +- /blog/getting-ready-for-11.html +date: '2013-05-05' +author: Shai Almog +--- + +![Header Image](/blog/getting-ready-for-11/codename-one-charts-1.png) + +As part of our preparation for the 1.1 version of Codename One we are accelerating our typical release cycle so we can test against regressions as soon as possible. We plan to make a release within this month for versions 1.1. + + +The final feature set for 1.1 should include the following highlights: + + * [ +3rd party Library support +](http://www.codenameone.com/3/post/2013/02/new-preliminary-library-support.html) + + + + * [ + +Windows Phone 8 support + +](http://www.codenameone.com/3/post/2013/04/windows-phone-8-and-the-state-of-7.html) + * [ +Side menu functionality +](http://www.codenameone.com/3/post/2013/02/hamburger-sidemenu.html) + * [ +Pull to refresh +](http://www.codenameone.com/3/post/2013/03/pull-to-refresh-several-new-how-do-i-videos.html) + * [ +OTA Device Skin downloads +](http://www.codenameone.com/3/post/2013/04/ota-device-skin-downloads.html) + * [ +S40 Improvements +](http://www.codenameone.com/3/post/2013/04/j2me-feature-phones-nokia-devices.html) + + * [ +Cloud object viewer tool +](http://www.codenameone.com/3/post/2013/04/cloud-object-viewer.html) + + * [ +Component inspector tool +](http://www.codenameone.com/3/post/2013/02/inspecting-components.html) + * [ +On/Off Switch +](http://www.codenameone.com/3/post/2013/04/turn-it-on-or-off.html) + * [ +Pingjam integration +](http://www.codenameone.com/3/post/2013/04/pingjam-a-new-way-to-make-money-on-ads.html) + * (And maybe a couple of additional surprises!) + +So if you run into an issue in the next couple of weeks please +** +contact us immediately +** +so we can squash it before the release. Thanks! + + + + + + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/git-clone-and-run-project-from-cli.md b/docs/website/content/blog/git-clone-and-run-project-from-cli.md new file mode 100644 index 0000000000..5fb3442dfb --- /dev/null +++ b/docs/website/content/blog/git-clone-and-run-project-from-cli.md @@ -0,0 +1,162 @@ +--- +title: Clone and Run Codename One Demos In Single Line of Code +slug: git-clone-and-run-project-from-cli +url: /blog/git-clone-and-run-project-from-cli/ +original_url: https://www.codenameone.com/blog/git-clone-and-run-project-from-cli.html +aliases: +- /blog/git-clone-and-run-project-from-cli.html +date: '2017-11-27' +author: Steve Hannah +--- + +![Header Image](/blog/git-clone-and-run-project-from-cli/tip.jpg) + +We have loads of demo Codename One apps hosted on Github, however cloning and running a project can be a little tricky because we generally don’t publish the dependent jar files (e.g. CodenameOne.jar) in the Github repository. This helps keep the repository lean, but it adds some steps to the process of cloning and running the project. + +For use cases like this, you may want to try the [Codename One CLI tool](https://www.npmjs.com/package/codenameone-cli), as it provides many useful functions directly on the command line. In this post I’ll demonstrate how you can easily clone a Codename One project from Github and run it in the Codename One simulator using a single line of code. + +Consider the [KitchenSink](https://github.com/codenameone/KitchenSink) demo. We can clone this repository using the following command + + + $ cn1 git-clone https://github.com/codenameone/KitchenSink + Cloning into 'KitchenSink'... + Installing jars into KitchenSink... + Downloading 11606508 bytes + Download completed! + Project ready at KitchenSink + +**What just happened?** + +The `cn1 git-clone` command is a thin wrapper around `git clone` (which implies that you need to have `git clone` in your PATH). Therefore you can pass it the same parameters as you pass to `git clone`. After cloning the repository, `cn1 git-clone` downloads the latest Codename One libs and adds them to the project so that it is ready to roll. + +**Running the Demo** + +Now that the project is cloned, we can run the demo in the Codename One simulator by running the “run” target of the project. E.g. + + + $ cd KitchenSink + $ ant run + +### Combining it into a Single Line + +If you are on Mac/Linux, it is easy to use the ‘&&’ operator to combine all this into a single line: + + + $ cn1 git-clone https://github.com/codenameone/KitchenSink && cd KitchenSink && ant run + +This clones it, changes to the KitchenSink directory, and runs it. + +### Finding Existing Demos + +You can also use the `cn1 list-demos` command to find existing Codename One demos on Github that you can clone. E.g. + + + $ cn1 list-demos + +This will produce a list of all of the repositories on Github that are tagged with both the “codenameone” topic, and the “demo” topic. The output will look like + + + shannah/GeoVizDemo : A demo app using the Codename One GeoViz Library + codenameone/KitchenSink : Rewrite of the kitchen sink demo to match design aesthetics of 2016 + ... etc.. + +You can filter the results by adding a parameter. + + + $ cn1 list-demos "GeoViz" + +This will only show demos that also match the GeoViz search. We have only just started tagging our demos so for now there aren’t very many listed there. But the list will grow as time goes on. + +__ | `cn1 list-demos` uses the Github search API, so you can use any filters that you would put into searches on the Github website. +---|--- + +Once we see a demo that we want to run, we can pass its full name to `cn1 git-clone`. E.g. + + + $ cn1 git-clone shannah/GeoVizDemo + +__ | This demonstrates that git-clone allows you to omit the `` from the repository name, and just provide the full repository name of the form `ownername/repositoryname` +---|--- + +### Adding Your Own Demos + +Adding your own demos so that they will be included in the `cn1 list-demos` results is easy. If your project is already hosted on Github, you simply need to add the `codenameone` and `demo` topics to the repository. + +__ | When hosting a project on Github I recommend stripping out all of the jar files just as we do in our demos. You can do this by simply copying the following directives into your `.gitignore` file +---|--- + +The `.gitignore` contents from the KitchenSink repository + + + *.jar + nbproject/private/ + build/ + nbbuild/ + dist/ + lib/CodenameOne_SRC.zip + *.p12 + *.mobileprovision + +A shortcut would also be to use `cn1 git-init` instead of `git init` when you initialize the repository. + +### Appendix: Installing the CLI Tool + +Thus far, I’ve skipped the step of actually installing the CLI tool. It is distributed using `npm`, which is included when you install [NodeJS](https://nodejs.org/en/), which has a simple installer for Windows, Linux, and Mac. + +**Installing Globally** + +Installing globally on Windows (Requires Admin permissions) + + + npm install -g codenameone-cli + +Installing globally on Mac/Linux + + + sudo npm install -g codenameone-cli + +**Installing Locally** + +If you don’t have admin permissions, or you just want to install it in the current directory, you can omit the `-g` flag. Then installation becomes + +Installing locally + + + npm install codenameone-cli + +This will install the command at `./node_modules/.bin/cn1` + +### Screencast + +I’ve create a short screencast demonstrating the use of the `cn1 git-clone` command. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Nick Koirala** — November 29, 2017 at 3:36 am ([permalink](https://www.codenameone.com/blog/git-clone-and-run-project-from-cli.html#comment-23689)) + +> Nick Koirala says: +> +> Nice one. Makes the demo projects much more accessible. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgit-clone-and-run-project-from-cli.html) + + +### **Mohammed Kamal** — November 12, 2019 at 2:56 pm ([permalink](https://www.codenameone.com/blog/git-clone-and-run-project-from-cli.html#comment-24266)) + +> [Mohammed Kamal](https://lh3.googleusercontent.com/a-/AAuE7mCCX8URBU8WJDWqV22i4h7HBcx_AKz6hh_WX4-U) says: +> +> Steve, excellent, just done this now .. better late than never! Many thanks for that, saved me lots of times. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgit-clone-and-run-project-from-cli.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/github-migration-completed.md b/docs/website/content/blog/github-migration-completed.md new file mode 100644 index 0000000000..bb3d77ca6d --- /dev/null +++ b/docs/website/content/blog/github-migration-completed.md @@ -0,0 +1,85 @@ +--- +title: Github Migration Completed +slug: github-migration-completed +url: /blog/github-migration-completed/ +original_url: https://www.codenameone.com/blog/github-migration-completed.html +aliases: +- /blog/github-migration-completed.html +date: '2015-03-28' +author: Shai Almog +--- + +![Header Image](/blog/github-migration-completed/github-logo.jpg) + +Its been a long weekend, but now that its finally over the long and tedious migration to github is almost completely +behind us. +Make sure to update your URLs to the new repository at +. +There are still some references to the old google code repository in the plugins etc. so you should update +them when we release the next update. Furthermore, if you used our custom update centers make sure your +update center doesn’t reference a googlecode URL! + +### New Structure + +Since github encourages smaller repositories we decided it might be a good idea to split up some non-core +pieces of the project. So we moved the demos to the +[codenameone-demos](https://github.com/codenameone/codenameone-demos) +project and the device skin UI resources were moved to +[codenameone-skins](https://github.com/codenameone/codenameone-skins). +We also removed some big directories containing the javadocs, repositories etc. Those are all mapped to +server locations on codenameone.com now. + +Another big change is the removal of all the jar, zip and other dependencies that might be required for the +project build. These were major size contributors and allowed us to bring the project size down to a very manageable +size. Right now we are still mapping the files that are “really needed” vs. the ones that just should never +have been committed. +We created a new project called +[cn1-binaries](https://github.com/codenameone/cn1-binaries) that contains +all those binaries. You will need to have it on the same level as the main cn1 project for everything to compile +properly. I’m not sure if this is OK with the github guidelines if not we will find another solution. + +### The Migration + +The migration was remarkably painful, the manual issue export code from Google didn’t work on Mac OS and there +were no public workaround. Its a Python script that assumes the users are familiar with python environments +in a typical Google hackish sort of way. Eventually I just purchased a droplet instance from Digital Ocean and +performed the migration in the cloud, this has the benefit of using a very fast networking pipeline which made a +lot of the work way faster even though I was working on a remote shared instance. It also made the python code +work since for things such as this Linux instructions are easier than the Mac OS instructions. + +Some issue meta-data didn’t transfer well, they are all marked as if I added them and then added all the comments +which is pretty lame for a migration script. So you should make sure to signup to the issues you submitted and +make sure everything you provided is still there (e.g. test cases). + +Source migration was even more painful, it took roughly 15 attempts to get it right. The git-svn scripts all failed badly on +fetching the repository during the GC phase and the only way we were eventually able to do this was thru +the direct svn command like this: + + + git svn clone https://codenameone.googlecode.com/svn/trunk -A .authors.txt . --no-metadata + +Notice that we used the `--no-metadata` tag which is discouraged, it just didn’t work otherwise. We also +pointed to the trunk thus discarding branch and tag data since we didn’t see any other way of getting this to work… + +Unfortunately, this was only the beginning. We ended up with a 7.4gb workspace which is obviously way too much… +Following the instructions to remove directories and all their history we ended up with a 10gb repository +(seriously…). Pruning data from a version control system is always difficult (this isn’t a GIT specific issue). +Despite running the git gc with the aggressive and prune flag the size was still pretty huge. + +Eventually the only thing that worked in shrinking the repository was to clone it to a new location using +the file: URL path e.g.: + + + git clone file:///path/project.git . + +Notice the . in the end indicating the empty current directory as the destination. +Once this was done we were able to split the repository to smaller repos and now we have the new +structure above while maintaining as much history as possible. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/github-migration-plan.md b/docs/website/content/blog/github-migration-plan.md new file mode 100644 index 0000000000..3caa8a26a8 --- /dev/null +++ b/docs/website/content/blog/github-migration-plan.md @@ -0,0 +1,92 @@ +--- +title: Github Migration Plan +slug: github-migration-plan +url: /blog/github-migration-plan/ +original_url: https://www.codenameone.com/blog/github-migration-plan.html +aliases: +- /blog/github-migration-plan.html +date: '2015-03-23' +author: Shai Almog +--- + +![Header Image](/blog/github-migration-plan/github-logo.jpg) + +As you may know Google is ending support for Google code effectively forcing us to migrate to github. While +we like a lot of things about github their 1gb per workspace restriction makes the migration process rather difficult +since we have to manually delete some histories for binary files we committed into SVN. +Making matters worse, Google’s so called “automated tools” are ridiculously simplistic and don’t support anything +like this or migration of more than 1000 issues! + +This effectively means we will need to perform the migration manually, we will probably discard the existing tags +but we will try to preserve workspace history and the issues. This Friday we will close the issue tracker, all new issues +will be ignored, we will then move all the issues to a new github project that we will create for this purpose. +We will also move the code base and all future commits to the new repository but since commits are currently limited +to Codename One team members this shouldn’t be a problem. + +Once we will finish the migration we will leave the existing project in Google code for reference purposes. + +Hopefully we will finish the migration process over the weekend but from past experience I’m rather pessimistic. +The svn2git tools were pretty badly broken the last time we checked them. +Hopefully our prior experience with such migration attempts will soften the blow and make the process easier +this time around. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Alexandre Richonnier** — March 28, 2015 at 1:24 pm ([permalink](https://www.codenameone.com/blog/github-migration-plan.html#comment-22248)) + +> Alexandre Richonnier says: +> +> Maybe you could give a chance to bitbucket? +> +> For open source projects, there ‘s no limit. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgithub-migration-plan.html) + + +### **Shai Almog** — March 28, 2015 at 3:01 pm ([permalink](https://www.codenameone.com/blog/github-migration-plan.html#comment-22261)) + +> Shai Almog says: +> +> We looked at that and several others. While I’d love that it does seem that pretty much everyone is going to Github. +> I like Github in general, the site and tools are amazing. I think the main problem is git itself but since most people are moving in that direction we should probably align rather than fight it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgithub-migration-plan.html) + + +### **cvconover** — August 11, 2015 at 12:58 pm ([permalink](https://www.codenameone.com/blog/github-migration-plan.html#comment-22435)) + +> cvconover says: +> +> Shai, +> +> Just wondering what you do not like about git. It is the first vcs that I actually enjoyed working with from the command line. +> +> Cheers +> Craig +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgithub-migration-plan.html) + + +### **Shai Almog** — August 11, 2015 at 2:02 pm ([permalink](https://www.codenameone.com/blog/github-migration-plan.html#comment-21545)) + +> Shai Almog says: +> +> Actually I like GIT much better now with the improved tooling (3 years made a big difference). +> I love distributed versioning and loved it at Sun where it was pioneered (the guy that inspired Linus to write GIT and effectively outlined its architecture == ex Sun guy). +> The main issue I had with GIT back then was that its conflict resolution approach was HORRIBLE, this has been greatly improved and is now in SVN level. The secondary issue was that it encrypts everything, which is great for a commercial project but for an open source project its not very useful. We had a conflict and merge broke down badly, unfortunately because everything was encrypted we effectively lost the data and couldn’t find it in history. With the old Sun unencrypted tools (SCCS) and even with SVN everything is stored as text files and if something goes wrong you can just look thru that. +> +> Overall, I’m much happier with Git today and I’m generally happy we made the move. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgithub-migration-plan.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/go-for-it.md b/docs/website/content/blog/go-for-it.md new file mode 100644 index 0000000000..c0cdd3d99f --- /dev/null +++ b/docs/website/content/blog/go-for-it.md @@ -0,0 +1,34 @@ +--- +title: Go for it! +slug: go-for-it +url: /blog/go-for-it/ +original_url: https://www.codenameone.com/blog/go-for-it.html +aliases: +- /blog/go-for-it.html +date: '2017-03-12' +author: Shai Almog +--- + +![Header Image](/blog/go-for-it/full-stack-java-bootcamp.jpg) + +I want the bootcamp to sell out fast. Since the number of spots is very limited this should be doable. To make this happen we are adding to the bootcamp: + + * **2 months of enterprise subscription** (worth $798) + + * **Free access to upcoming & current courses** (worth $398) + + * **Two one on one sessions with me** (you’d be shocked at how much I used to charge per hour as a consultant) + +And that is on top of the 4 weeks of material and a full blown startup worth of progress made in a single bootcamp. We did on-site training that included far less than this for 5K per seat last year! + +The signup page is [here](https://codenameone.teachable.com/p/full-stack-java-mobile-app-bootcamp/) and contains a lot of additional details. + +P.S Even if this sells out quickly I won’t do another one of these. It’s too exhausting and I need to focus on Codename One. I want to keep this post brief but in my update later in the week I’ll elaborate a bit more on why. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/good-looking-by-default-native-fonts-simulator-detection-more.md b/docs/website/content/blog/good-looking-by-default-native-fonts-simulator-detection-more.md new file mode 100644 index 0000000000..9022841748 --- /dev/null +++ b/docs/website/content/blog/good-looking-by-default-native-fonts-simulator-detection-more.md @@ -0,0 +1,152 @@ +--- +title: Good Looking By Default, Native Fonts, Simulator Detection & More +slug: good-looking-by-default-native-fonts-simulator-detection-more +url: /blog/good-looking-by-default-native-fonts-simulator-detection-more/ +original_url: https://www.codenameone.com/blog/good-looking-by-default-native-fonts-simulator-detection-more.html +aliases: +- /blog/good-looking-by-default-native-fonts-simulator-detection-more.html +date: '2015-11-15' +author: Shai Almog +--- + +![Header Image](/blog/good-looking-by-default-native-fonts-simulator-detection-more/new-hello-world-look.jpg) + +I’ve spent a lot of time working with and reviewing other cross platform tools this past month, mostly with Cordova +due to [our recent announcement that +we support Cordova](/blog/phonegap-cordova-compatibility-for-codename-one.html). +I hope it doesn’t come off as too arrogant but our “onboarding” experience is pretty amazing in comparison +to pretty much everything else. Just install IDE, type in Codename One and follow wizard for new app. +The only tools that are simpler than that are the rather limited web based solutions. +But we do fall short in one major way, our “hello world” apps look bad by default when compared to pretty much +any tool out there. There are a lot of reasons for this but none of them are good reasons and this gives a horrible +first impression to any developer picking up Codename One for the first time. + +E.g. this is what our new Hello Cordova demo looks like when creating a hello world on Codename One: + +![Cordova Hello World App](/blog/good-looking-by-default-native-fonts-simulator-detection-more/hello-cordova.png) + +What isn’t obvious in this screenshot is that the text on the bottom animates in a very pleasant subtle way +to complete the experience. It just looks great and inviting to explore! +By comparison this is what we have today if you just use the new project wizard all the way thru without +changing the defaults: + +![Codename One Hello World](/blog/good-looking-by-default-native-fonts-simulator-detection-more/hello-codenamene.png) + +I think picking the flat blue theme as the default would be a slight improvement but this is not an inviting +first impression. We created this because we think like developers (“get a hello world out”) but we should +think like a product where the end result matters. +Several things need fixing here: + + * Default color scheme – the blue theme should be the default, lighter more inviting colors + * We need better more modern fonts by default – see below + * We need a more animated/image based output + * We still want to keep the code short and simple + +So right now this is what we have in terms of a new “hello” world, the Apple logo in dukes hand +is replaced dynamically with android/windows logos: + +![New Codename One Hello World](/blog/good-looking-by-default-native-fonts-simulator-detection-more/new-hello-codenamene.png) + +The code for this entire thing is pretty small as well so it should be really easy. +Notice that we will still have the plain hello world app, “we’ll just rename it to “barebones” which is more +representative of its function/use. + +#### Simpler Fonts + +Fonts have always been a hassle with Codename One because of the low end platform legacies. The main +problem is that even if we want to support something like truetype fonts only on smartphones, we still need +to change rather complex API’s and the designer UI. + +We normally just recommend that people embed a TTF file which solves the problem for some use cases, but +its often not intuitive and doesn’t work well for the “good looking by default” goals stated above. Modern Android +devices have roboto font builtin to them and modern iOS devices have HelveticaNeue both are gorgeous fonts +that can really make a huge difference to an app. +So we introduced a new scheme into the `Font.createTrueTypeFont` method, if you use one of +the hardcoded font names on a device that supports it you will get a font object that is similar to a TTF loaded +font but was generated by the platform. To detect if a platform supports this use `Font.isNativeFontSchemeSupported`. + +This might be challenging for most developers so we enhanced the designer to include all of the options: +`native:MainThin`, `native:MainLight`, +`native:MainRegular`, `native:MainBold`, +`native:MainBlack`, `native:ItalicThin`, +`native:ItalicLight`, `native:ItalicRegular`, +`native:ItalicBold`, `native:ItalicBlack`. +Each option here maps to either roboto on Android or HelveticaNeue on iOS with the equivalent weight/italic +behavior. + +#### Detecting The Simulator/Simpler Crash Reports + +One of the long time requests we always had was detecting whether we are running in the simulator or not. +In the past no one opened an issue on that and most were OK with using some `System.getProperty()` +trickery. +While these tricks work, they still have issues with the desktop port. There is also the very valid use case of +detecting the simulator to disable crash protection and to implement development time logic (e.g. skipping login process). + +We now have a new method in `Display`: `isSimulator` which I would say is pretty +self explanatory. +One of the triggers for this is the new `Log.bindCrashProtection(boolean)` API which ignores +the simulator and doesn’t bind crash protection logic there. This method accepts a boolean flag indicating whether +the exception on the EDT should be swallowed. It simply grabs all exceptions thrown on the EDT and sends the +log to us by email, its restricted to pro developers as part of the crash protection feature.. + +#### More Terse Layouts + +We added a lot of new terse layout API’s into the layout class specifically `LayeredLayout` now +has an `encloseIn` method of its own. So does `FlowLayout`, however it also added +many methods to allow enclosing in all the available variation of flow loyout types, specifically: +`encloseCenter`, `encloseRight`, `encloseMiddle`, +`encloseCenterMiddle`, `encloseRightMiddle`, `encloseBottom`, +`encloseCenterBottom`, `encloseRightBottom`. + +#### New Label Constructors + +We recently added the ability to create a `Label` with UIID and now we added the ability to +create a label with both text and an image in a single constructor (I’m a bit shocked we didn’t have this). +We also added a constructor for text, image and a UIID. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — November 17, 2015 at 9:25 am ([permalink](https://www.codenameone.com/blog/good-looking-by-default-native-fonts-simulator-detection-more.html#comment-22443)) + +> Chidiebere Okwudire says: +> +> The new ‘hello world’ is definitely more attractive… Personally though, if feels less ‘CN1-like’. Why not the image/animation in the kitchen sink demo splashscreen? [http://www.codenameone.com/…]() That includes the CN1 logo, a nice animation and is also pretty in my opinion. +> +> BTW: There’s a typo in the text: “Lets” should be “Let’s” +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-looking-by-default-native-fonts-simulator-detection-more.html) + + +### **Shai Almog** — November 18, 2015 at 3:43 am ([permalink](https://www.codenameone.com/blog/good-looking-by-default-native-fonts-simulator-detection-more.html#comment-22377)) + +> Shai Almog says: +> +> Thanks! +> Fixed the Let’s typo. +> +> I liked the usage of the mascot that Cordova did and I always liked Duke, I think he is more recognizable than our logo. Being at JavaOne you see grown men stand in line for a photo-op with duke (and James Gosling who I guess is the human version of Duke). I did think about photoshopping a Codename One Tattoo on his belly though and I might just do it. +> +> The beaker says to me that this is a Lab (like the kitchen sink was), its also a “one off” animation so if you run it and go get some coffee you come back and the animation is gone. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-looking-by-default-native-fonts-simulator-detection-more.html) + + +### **bankifsc codes** — December 15, 2015 at 4:53 am ([permalink](https://www.codenameone.com/blog/good-looking-by-default-native-fonts-simulator-detection-more.html#comment-22590)) + +> bankifsc codes says: +> +> [Mobile tracker with name and address]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-looking-by-default-native-fonts-simulator-detection-more.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/good-to-great.md b/docs/website/content/blog/good-to-great.md new file mode 100644 index 0000000000..f969d5e6b1 --- /dev/null +++ b/docs/website/content/blog/good-to-great.md @@ -0,0 +1,411 @@ +--- +title: Getting from Good to Great +slug: good-to-great +url: /blog/good-to-great/ +original_url: https://www.codenameone.com/blog/good-to-great.html +aliases: +- /blog/good-to-great.html +date: '2017-06-20' +author: Shai Almog +--- + +![Header Image](/blog/good-to-great/deep-dive-into-mobile.jpg) + +Thanks for all the great feedback on my [last post](/blog/thats-great-looking-app.html), I got some wonderful app suggestions from some of you and some interesting questions. Overall, there were more than 100 comments and emails so I apologize if I took too long to answer some of you. I already mentioned the focus of these coming courses is to let you create apps in a more practical form: “cook book” style. +But while I talked a bit about the narrative and the course I didn’t explain exactly how or why this will work effectively. + +One of the core capabilities of Codename One is control over every pixel in the screen. It’s a huge benefit and also a double edged sword…​ + +When wielded properly you can leverage this ability to create custom, fluid UI’s that seamlessly match the native OS style and form. But with great power comes great responsibility and we can end up with apps that…​ I’m sure you can complete that sentence…​ We’ve all seen those apps and I don’t want you to be there. + +Recently I explained how we can create a [gorgeous side menu](/blog/tutorial-create-a-gorgeous-sidemenu.html) design with very few steps. That’s one of the things I picked up from the bootcamp. Everyone had issues with something that should be as simple as a side menu. But that’s just the tip of the iceberg when you are building a full fledged app. That’s exactly what I aim to fix with this new material. + +### Feedback + +After my last post I received a lot of questions & suggestions that I’d like to address: + +**Do I need to Know Anything?** + +You need to know Java to a reasonable degree. You don’t need prior knowledge in Codename One though. I’d love to add an “introduction to Java” course to the mix but that might be stepping outside of my personal comfort zone. + +**Will you use Youtube?** + +One of the questions focused on youtube mostly because of their excellent subtitle support which makes the videos more accessible to foreign language speakers and the hearing impaired. + +I’ll use the teachable platform which allows me to structure course material and provide solutions, presentations etc. as part of the course. In some of the presentations I also include a transcript of the video with the slides, this should help fill in the gaps. I’m not sure if I’ll be able to walk the way back and do that for the older videos but since it’s already done for a lot of the videos it shouldn’t be a problem. + +**What sort of material will be covered?** + +We will [launch with the restaurant and the “app builder”](/blog/restaurant-app-builder.html) as part of the initial launch material. This is some of the material I developed for the bootcamp “remastered” to a more refined flow. + +A major focus of the material is refining the look of the application, working with themes and design. But this is just a tip of the iceberg as the material covers everything that you need to bring an app to production. From security, to application architecture, native interfaces, sql, ORM, backend VPS setup and everything in between. + +Notice I’ve made a specific distinction for “launch material”, for the next two years at least we will add a new module every month. Guaranteed! + +**Shouldn’t Codename One be Good Looking by Default?** + +This isn’t exactly a question that was asked but it was an underlying current. + +The answer is yes. We are are working on improving the default look for applications so if you create a hello world and start adding components without knowing much you should get something that looks decent. + +This material would still be valuable even as we improve the basic look, everything that I teach would be just as applicable in the future as it is now. I’ll also update materials with newer details as features and enhancements make their way out. + +### Real Apps + +I’ve mentioned the importance of “real world” apps in my last post and asked for some feedback to get a sense of what sort of apps you are building. You really came through with a lot of great suggestions! + +I worked on them a bit to unify some of the ideas that are similar and came up with a set of initial suggestions: + + * Taxi hailing app (Uber clone) + + * Instant messaging app (whatsapp clone) + + * Social media app (instagram/facebook style) + + * Side scrolling game (mario style) + + * Point of sale app (charging and invoicing) + + * Image editor app (finger paint style app) + + * Kids puzzle game + + * Client Server business management app with database synchronization + + * Client Server business management app with Parse backend + + * Music player app + + * Video player app + + * Camera app – photos with overlay images on top + +If you can think of other ideas for such apps that you would like to see please use the comments section below for ideas. + +I’ve narrowed this list down to the top 4 most requested apps and I’ve made a voting form you can use to select the apps that you think I should add first to the course [click here](https://goo.gl/forms/XpiKZp8JPj5fhWTQ2) to select the app. + +### Before I sign Off + +Today we entered the code freeze and released a release candidate of Codename One 3.7 plugins. That means you should be able to update the plugins for all major IDE’s and get the latest version of Codename One. Please bang on it a bit and let us know if there are major regressions. + +### So What’s Next? + +In the next piece I’ll explain the details of how the whole thing will work and why I chose to go with exactly 3 courses…​ + +As always I really appreciate the comments and feedback, if you have thoughts or questions please let me know. And please don’t forget to [vote](https://goo.gl/forms/XpiKZp8JPj5fhWTQ2)! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Dalvik** — June 21, 2017 at 11:22 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-21850)) + +> Dalvik says: +> +> Do we get an “I voted” badge on our account 😉 +> +> +1 for the Uber demo. +> Downloading 3.7 RC right now! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 21, 2017 at 11:41 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23415)) + +> Shai Almog says: +> +> Based on the first few votes, the Uber clone looks like it will win in a landslide… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Kolawole Tajudeen** — June 21, 2017 at 11:43 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-21861)) + +> Kolawole Tajudeen says: +> +> Point of sale app sounds great +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Andrew Ughonu** — June 21, 2017 at 11:55 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23495)) + +> Andrew Ughonu says: +> +> Social media app (instagram/facebook style) will juust do it. Thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **salah Alhaddabi** — June 21, 2017 at 12:54 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23252)) + +> salah Alhaddabi says: +> +> Dear Shai, in general if you can have one business app and one social app will be great. Your listed apps also look great and thanks a lot for your interaction with your customers as i have never seen this being done anywhere with other development platforms. Thanks a lot!!! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Dalvik** — June 21, 2017 at 12:58 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23112)) + +> Dalvik says: +> +> I second that! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 21, 2017 at 1:27 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23610)) + +> Shai Almog says: +> +> Thanks. Would love to do that but it’s probably something that will have to wait for a while. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 21, 2017 at 1:29 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23411)) + +> Shai Almog says: +> +> Based on current voting it’s 3rd by a narrow margin behind whatsapp style app. I initially expected this to be a tighter race but Uber style app is so far ahead I doubt this will change. But I’ve been surprised by these things before. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 21, 2017 at 1:31 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23275)) + +> Shai Almog says: +> +> Thanks! +> Companies that originate from open source projects tend to have a relatively open culture. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Francesco Galgani** — June 21, 2017 at 2:12 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23451)) + +> Francesco Galgani says: +> +> I voted for the social app 🙂 +> Are the new courses free or with fee? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **3lix** — June 21, 2017 at 2:48 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23356)) + +> 3lix says: +> +> I think there are lot of materials covering social style app even though it is spread across the documentation, blog, stackoverflow, google groups etc… +> But there aren’t any materials detailing an Uber style app. +> +1 Uber (style) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 21, 2017 at 3:09 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23517)) + +> Shai Almog says: +> +> This is the current status of the votes, Uber style has a solid lead but it’s narrowing from a 80%. I still think it will come on top… +> [https://uploads.disquscdn.c…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 21, 2017 at 3:10 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23579)) + +> Shai Almog says: +> +> Agreed, it is indeed a missing piece. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Roman H.** — June 21, 2017 at 4:05 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23611)) + +> Roman H. says: +> +> One more for Client Server business management, I am just investigating now to build up a mobile reporting prototype. @Shai regarding the data processing please focus on JSON and CVS and let the companies backend guys to build their own API to handle their conversion from SQL to CVS / JSON. It will strip you multiple DB engine handling while you can focus on chart and graph implementation. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **John Barrett** — June 21, 2017 at 4:53 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23592)) + +> John Barrett says: +> +> Thanks Shai. These look great! I’m very interested in the Client server business apps. I look forward to learning more about all of these, though! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 22, 2017 at 4:19 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-21862)) + +> Shai Almog says: +> +> We focus only on the things necessary in the client. In the online course the server code is designed as a simple instruction tool and not meant to replace proper training in server development tools. The main reason we have it is for small shops/teams that need to do everything. I think having decent understanding of what the server guys do is important for mobile developers just like it’s important for us to understand what a UI designer does and his process. +> +> Notice we have SQL on the device itself (sqlite) and we use it for some storage and processing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 22, 2017 at 4:22 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23488)) + +> Shai Almog says: +> +> The material launches with 2 applications which are the restaurant app and builder app. Technically both are client server app and I spend a lot of time discussing the communication, responsibility, webservices etc. +> +> In the final segments I cover it all the way to the deployment of the server in the VPS. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Riper3-3** — June 22, 2017 at 7:42 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23396)) + +> Riper3-3 says: +> +> Hello! I think an awesome app would be something to do with IoT, connecting to something like an arduino with Bluetooth, and then sending it relevant data. This would probably have to work with only one type of IoT device… or the possibilities would be too many. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 22, 2017 at 9:45 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23634)) + +> Shai Almog says: +> +> Thanks. +> I love these demos when I go to shows as it’s really cool to see something physical working. But for an online course they are a huge problem as you can’t possibly get hardware out to people. +> +> I thought about getting a BluetoothLE app but even there the hardware is a bit problematic and I’m not exactly sure what I’ll do. +> +> This is indeed interesting especially for me as a guy with heavy background in robotics I just love this stuff and would love to build something cool with mindstorms and my kids. But it might be a bit too much. +> +> Anyway, if more people ask for it I’m game. We had a lot of interest over bluetooth and IoT recently but it was all over the place so it’s hard for me to know for sure what will work and for whom. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Sibasish Mohanty** — June 22, 2017 at 11:06 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23570)) + +> Sibasish Mohanty says: +> +> Hi Shai,Gr8 line of apps you suggested. I will go with the uber app as the main thing in that is map interface.And if possible can you plz give a demo chat app on firebase? And Will the uber clone will on Mapbox or Gmap? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Andrew Nyago** — June 22, 2017 at 11:31 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23357)) + +> Andrew Nyago says: +> +> some of us from less accessible places would appreciate if some time is given for us to get access to the hardware… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 22, 2017 at 2:55 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23458)) + +> Shai Almog says: +> +> Thanks. That’s pretty much the winner so far. We will use Google Maps as that is the integration we already have. +> We don’t currently support firebase. We have two chat demos already in the tutorials section. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **John Barrett** — June 22, 2017 at 3:33 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23552)) + +> John Barrett says: +> +> Sounds great! Thank you sir… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **nasznjoka** — June 22, 2017 at 3:48 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23469)) + +> nasznjoka says: +> +> Sports feed apps. Real time broadcasting of sports events like live score +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 22, 2017 at 5:52 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23536)) + +> Shai Almog says: +> +> Thanks. I’m not really familiar with that field (not big on sports), what would that include technically? +> RSS? Audio/video streaming? +> Are there public sources I can use without violating rights? One of the problems with sports is digital rights and I don’t want to step into that mess. An RSS newsreader and streaming is interesting but I’ll need good sources/concepts for that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **adhiguna mahendra** — June 23, 2017 at 3:25 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-21521)) + +> adhiguna mahendra says: +> +> Definitely. Uber Style Taxi hailing app with complex backend logic! if you can develop this kind of app, you can build anything! me and my team developed realtime Transport Management Platform [www.sealtrax.com]() using native Android. It’s pain. Codenameone should make our job easier. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 23, 2017 at 4:35 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23496)) + +> Shai Almog says: +> +> That’s pretty much decided by the numbers already so it will be an Uber clone. I’m not going to do complex backend logic. I’ll keep it relatively simple in the backend. I think a lot of startups fail because they try to “build to scale” before they learn to walk… +> +> My goal is to show how off the shelf stuff can be used to make something like that, but obviously on the server side once you start to scale you would also scale that architecture. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Amuche Chimezie** — June 23, 2017 at 2:07 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23060)) + +> Amuche Chimezie says: +> +> Please can you share any major detailed link on the social style app that can be useful to me? I seem to be lost somehow on my project. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Amuche Chimezie** — June 23, 2017 at 2:08 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23202)) + +> Amuche Chimezie says: +> +> Open Source please? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Amuche Chimezie** — June 23, 2017 at 2:10 pm ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23600)) + +> Amuche Chimezie says: +> +> Can we please consider a touch on the Social media app a little? 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + + +### **Shai Almog** — June 24, 2017 at 5:14 am ([permalink](https://www.codenameone.com/blog/good-to-great.html#comment-23156)) + +> Shai Almog says: +> +> The second app after the Uber app might be a social media app based on the current voting. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgood-to-great.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/gradient-image-background-floatingactionbutton.md b/docs/website/content/blog/gradient-image-background-floatingactionbutton.md new file mode 100644 index 0000000000..9a8090cabb --- /dev/null +++ b/docs/website/content/blog/gradient-image-background-floatingactionbutton.md @@ -0,0 +1,43 @@ +--- +title: Gradient and Image Background on FloatingActionButton +slug: gradient-image-background-floatingactionbutton +url: /blog/gradient-image-background-floatingactionbutton/ +original_url: https://www.codenameone.com/blog/gradient-image-background-floatingactionbutton.html +aliases: +- /blog/gradient-image-background-floatingactionbutton.html +date: '2016-11-01' +author: Shai Almog +--- + +![Header Image](/blog/gradient-image-background-floatingactionbutton/gradients-image-background-floatingactionbutton.jpg) + +The Phoenix theme had a [FloatingActionButton](/blog/floating-button.html) with a gradient on top. This goes against the mostly flat material +design spec but after looking at the design with a solid color I came to the conclusion that the designer was totally +right to use a gradient in this case. Unfortunately we didn’t build that support into the `FloatingActionButton`. + +So as part of that work I added a special mode to the `RoundBorder` that uses the parent UIID to draw the background. +This sounds like a “no brainer” but there is a catch: the round border needs to be “round”. + +Gradient and image primitives don’t draw within a round shape, so the only solution was +[shape clipping](/blog/shape-clipping-bubble-transition.html) which has a performance penalty as well +the associated problem of not working everywhere…​ + +So right now this is off by default as the behavior doesn’t work exactly the same on the JavaScript or Windows ports +where shape clipping is still missing. + +To enable this we need to change the border of the component by making it use the UIID. We need to do that +from code using the `RoundBorder.uiid(boolean)` method. We can do this using: + + + RoundBorder rb = (RoundBorder)fab.getUnselectedStyle().getBorder(); + rb.uiid(true); + +If the background style of the round border includes a gradient or an image you will see the effects at once. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/gui-builder-improvements-3-7.md b/docs/website/content/blog/gui-builder-improvements-3-7.md new file mode 100644 index 0000000000..46af14265e --- /dev/null +++ b/docs/website/content/blog/gui-builder-improvements-3-7.md @@ -0,0 +1,361 @@ +--- +title: GUI Builder Improvements +slug: gui-builder-improvements-3-7 +url: /blog/gui-builder-improvements-3-7/ +original_url: https://www.codenameone.com/blog/gui-builder-improvements-3-7.html +aliases: +- /blog/gui-builder-improvements-3-7.html +date: '2017-06-27' +author: Steve Hannah +--- + +![Header Image](/blog/gui-builder-improvements-3-7/uidesign.jpg) + +With version 3.7, we have revamped the GUI builder with a designer that allows you to position your elements precisely where you want them. The experience should be closer to what you find in graphical design applications like Photoshop rather than the more rigid “drop in the slot” approach in previous versions of the GUI builder. There are caveats to be aware of with this approach, but overall, it should empower you to build beautiful UIs with greater ease than before. + +![Screenshot of new GUI Builder designer](/blog/gui-builder-improvements-3-7/guibuilder-2-screenshot.png) + +In this blog post I will be focusing on the low-level details of “how it works” so that you can understand how to best tune it to your liking. We will be producing additional demos, posts, and documentation that cover these changes from a higher-level perspective. + +## Background + +If you’ve used Codename One at all, you’re likely aware of its heavy usage of layout managers for positioning components on the screen. You don’t just place a button on the screen at a particular size and position. You would, instead, add the button to a container and have the container’s layout manager calculate the correct position for the button. If you wanted your components to be laid out across the screen and then wrap when it runs out of room, you would use FlowLayout. If you wanted to tile your buttons in a grid, you might use GridLayout. If you want to layout the buttons vertically down the page you would use a box layout Y. Etc.. In general, it is possible to reproduce any design from a PSD file by nesting components with the classical layout managers. + +### Why Can’t We Just Place A Component at some (x,y) Coordinate? + +Shai has written about this many times in the past. The long and short of it is that when your app is shown on a screen with different resolution or dimensions, the app may need to reposition the element. You need a layout manager that is able to dynamically calculate the appropriate position for your components based on the current state. + +Unfortunately, this explanation provides little consolation to new users who just want to drag a button onto the form where they want it, and run their app. To expect new users to understand layout managers before they can build their “Hello World” app is, perhaps, a little demanding. + +One key goal for this iteration of the designer was to make it more accessible to new users. I want a user to be able to drag labels, buttons, text fields, etc.. from the palette onto the form and position them freely, exactly how they like. I didn’t want them to have to worry about layout managers and the like. Just drag widgets around, and then run the app. + +### But Didn’t I Just Say that Absolute Positioning isn’t Practical? + +Indeed absolute positioning in a mobile application is not practical. Our solution is “relative” positioning. We have beefed up the layered layout manager to support insets and inter-component references, and we have added the ability to manipulate the layout using familiar drag-and-drop GUI designer controls. + +For example, if you drag a button down to the bottom corner of the form, the designer doesn’t save the absolute X,Y coordinate for the button. If saves the insets (distance) from that bottom corner. That way, at runtime, the button will always be rendered appropriately in the bottom corner no matter what the device dimensions are. + +Going a step further, if you then drag a text field just to the left of the button, the designer will record the text field’s insets relative to the button so that it will lay out properly still even as the device is resized. + +__ | The designer only automatically links the text field’s position to the button if “Smart Insets” is enabled. With “Smart Insets” disabled, you would need to link it explicitly. +---|--- + +The example with only two components may seem contrived, but we have worked hard to ensure that it can scale to arbitrary UI complexity with dozens of components positioned exactly the way you want. + +## Under the Hood + +Before we go into the designer’s UI, let’s take a moment to look at the new and improved Layered Layout manager, upon which all of this goodness rests. + +Pre-3.7, LayeredLayout simply laid out containers on top of each other in layers. It didn’t allow you to position the child components, except via margins and padding. + +In this release, we have kept the default behaviour the same, but have added support for constraints that add insets to child components. Here is a simple example that adds a button to the bottom, right corner of a container. + + + Container cnt = new Container(new LayeredLayout()); + Button btn = new Button("Submit"); + LayeredLayout ll = (LayeredLayout)cnt.getLayout(); + cnt.add(btn); + ll.setInsets(btn, "auto 0 0 auto"); + +The result is: + +![Button positioned in bottom right using insets](/blog/gui-builder-improvements-3-7/guibuilder-2-insets-1.png) + +The only thing new here is this line: + + + ll.setInsets(btn, "auto 0 0 auto"); + +This is called after `btn` has already been added to the container. It says that we want its insets to be “auto” on the top and left, and `0` on the right and bottom. This insets string follows the CSS notation of `top right bottom left` (i.e. start on top and go clockwise), and the values of each inset may be provided in pixels (px), millimetres (mm), percent (%), or the special “auto” value. Like CSS, you can also specify the insets using a 1, 2, or 3 values. E.g. + + 1. `"1mm"` – Sets 1mm insets on all sides. + + 2. `"1mm 2mm"` – Sets 1mm insets on top and bottom; 2mm on left and right. + + 3. `"1mm 10% 2mm"` – Sets 1mm on top, 10% on left and right, and 2mm on bottom. + + 4. `"1mm 2mm 1px 50%"` – Sets 1mm on top, 2mm on right, 1px on bottom, and 50% on left. + +### `auto` Insets + +The special “auto” inset indicates that it is a flexible inset. If all insets are set to “auto”, then the component will be centered both horizontally and vertically inside its “bounding box”. + +__ | The “inset bounding box” is the containing box from which a component’s insets are measured. If the component’s insets are not linked to any other components, then its inset bounding box will be bounds of the component’s parent container. +---|--- + +If one inset is fixed (i.e. defined in px, mm, or %), and the opposite inset is “auto”, then the “auto” inset will simply allow the component to be its preferred size. So if you want to position a component to be centered vertically, and 5mm from the left edge, you could do: + + + ll.setInsets(btn, "auto auto auto 5mm"); + +Resulting in: + +![Button vertically centered 5mm from left edge](/blog/gui-builder-improvements-3-7/guibuilder-2-insets-2.png) + +Move it to the right edge with: + + + ll.setInsets(btn, "auto 5mm auto auto"); + +### `%` Insets + +Percent (%) insets are calculated with respect to the inset bounding box. A 50% inset is measured as 50% of the length of the bounding box on the inset’s axis. E.g. A 50% inset on top would be 50% of the height of the inset bounding box. A 50% inset on the right would be 50% of the width of the inset bounding box. + +### Insets, Margin, and Padding + +A component’s position in a layered layout is determined as follows: (Assume that `cmp` is the component that we are positioning, and `cnt` is the container (In pseudo-code): + + + x = cnt.paddingLeft + cmp.calculatedInsetLeft + cmp.marginLeft + y = cnt.paddingTop + cmp.calculatedInsetTop + cmp.marginTop + w = cnt.width - cnt.verticalScroll.width - cnt.paddingRight - cmp.calculatedInsetRight - cmp.marginRight - x + h = cnt.height - cnt.horizontalScroll.height - cnt.paddingBottom - cmp.calculatedInsetBottom - cmp.marginBottom - y + +__ | The `calculatedInsetXXX` values here will be the same as the corresponding provided inset if the inset has no reference component. If it does have a reference component, then the calculated inset will depend on the position of the reference component. +---|--- + +If no inset is specified, then it is assumed to be 0. This ensures compatibility with designs that were created before layered layout supported insets. + +### Component References: Linking Components together + +If all you need to do is position a component relative to its parent container’s bounds, then mere insets provide you with sufficient vocabulary to achieve this. But most UIs are more complex than this and require another concept: reference components. In many cases you will want to position a component relative to another child of the same container. This is also supported. + +For example, suppose I want to place a text field in the center of the form (both horizontally and vertically), and have a button placed beside it to the right. Positioning the text field is trivial (`setInset(textField, "auto")`), but there is no inset that we can provide that would position the button to the right of the text field. To accomplish our goal, we need to set the text field as a reference component of the button’s left inset – so that the button’s left inset is “linked” to the text field. Here is the syntax: + + + Container cnt = new Container(new LayeredLayout()); + LayeredLayout ll = (LayeredLayout)cnt.getLayout(); + Button btn = new Button("Submit"); + TextField tf = new TextField(); + cnt.add(tf).add(btn); + ll.setInsets(tf, "auto") + .setInsets(btn, "auto auto auto 0") + .setReferenceComponentLeft(btn, tf, 1f); + +This would result in: + +![Button's left inset linked to text field](/blog/gui-builder-improvements-3-7/guibuilder-2-insets-3.png) + +The two active lines here are the last two: + + + .setInsets(btn, "auto auto auto 0") __**(1)** + .setReferenceComponentLeft(btn, tf, 1f); __**(2)** + +__**1** | Sets the left inset on `btn` to 0. +---|--- +__**2** | Links `btn’s left inset to `tf` so that it is measured from the text field. The third parameter (`1.0`) is the reference position. This will generally either be `0` (meaning the reference point is the left edge of the text field), or `1` (meaning the reference point is the right edge of the text field). In this case we set a reference position of `1.0` because we want the button to be aligned to the text field’s right edge. + +__ | The reference position is defined as the distance, expressed as a fraction of the reference component’s length on the inset’s axis, between the reference component’s leading (outer) edge and the point from which the inset is measured. A reference position of 0 means that the inset is measured from the leading edge of the reference component. A value of 1.0 means that the inset is measured from the trailing edge of the reference component. A value of 0.5 means that the inset is measured from the center of the reference component. Etc…​ Any floating point value can be used. The designer currently only makes use of 0 and 1. +---|--- + +The definition above may make reference components and reference position seem more complex than it is. Some examples: + + 1. **For a top inset** : + + 1. referencePosition == 0 ⇒ the inset is measured from the top edge of the reference component. + + 2. referencePosition == 1 ⇒ the inset is measured from the bottom edge of the reference component. + + 2. **For a bottom inset** : + + 1. referencePosition == 0 ⇒ the inset is measured from the **bottom** edge of the reference component. + + 2. referencePosition == 1 ⇒ the inset is measured from the **top** edge of the reference component. + + 3. **For a left inset** : + + 1. referencePosition == 0 ⇒ the inset is measured from the **left** edge of the reference component. + + 2. referencePosition == 1 ⇒ the inset is measured from the **right** edge of the reference component. + + 4. **For a right inset** : + + 1. referencePosition == 0 ⇒ the inset is measured from the **right** edge of the reference component. + + 2. referencePosition == 1 ⇒ the inset is measured from the **left** edge of the reference component. + +## The New Designer + +Now that you understand the basics of insets and reference components, let’s delve into the UI that we’ve designed to leverage this layout. The new GUI Builder includes a new designer that makes it a breeze to layout UIs. It allows you to drag components from the component palette onto the canvas just as you did before. The difference is that now you can move and resize your components exactly as you see fit. You aren’t constrained to the positions dictated by the form’s layout manager. + +As an example, let’s drag a button onto a blank form and see what happens. The button will be “selected” initially after adding, it so you’ll see its outline, and resize handles for adjusting its size and position. You’ll also see four floating labels (above, below, to the left, and to the right) that show the corresponding side’s inset values and allow you to adjust them. + +![Selected component in designer allows you to freely drag it to a new position](/blog/gui-builder-improvements-3-7/guibuilder-2-designer-selected-cmp.png) + +Press the mouse inside the bounds of the button and drag it around to reposition it. You will notice that the inset labels change to reflect the new inset values. If you drag the button close to the edge of the form, the corresponding inset value will change to millimetres. If you move farther away from the edge, it will change to percentage values. + +### The Inset Control + +Let’s take a closer look at the inset control (the inset controls are the black buttons that appear to the top, bottom, left, and right of the selected component). + +![Inset control](/blog/gui-builder-improvements-3-7/guibuilder-2-inset-control.png) + +Each control has three sections: + + 1. **The inset value drop-down menu**. This shows the current value of the inset (e.g. 0mm, 25%, auto, etc…​). If you click on this, it will open a menu that will allow you to change the units. If the inset is currently in millimetres, it will have options for pixels, and percent. If the inset is in percent, it will have options for pixels and millimetres. Etc.. It also includes a text field to enter a an inset value explicitly. + +![Inset drop-down menu](/blog/gui-builder-improvements-3-7/guibuilder-2-insets-dropdown-menu.png) + + 2. **The “Link” Button** ![Link button](/blog/gui-builder-improvements-3-7/guibuilder-2-link-button-unselected.png) – If the inset is linked to a reference component, then this button will be highlighted “blue”, and hovering over it will highlight the reference component in the UI so that you can clearly see which component it is linked to. Clicking on this button will open a dialog that will allow you to “break” this link. You can drag this button over any component in the form to “link”. + + 3. **The “Lock” Button”** ![Inset fixed button](/blog/gui-builder-improvements-3-7/guibuilder-2-inset-fixed-button.png) – This button allows you to toggle the inset between “flexible” (i.e. auto) and “fixed” (i.e. millimetres or percent). + +### Auto Snap + +Notice the “auto-snap” checkbox that appears in the top-right corner of the designer. + +![Auto-snap checkbox](/blog/gui-builder-improvements-3-7/guibuilder-2-smart-insets-auto-snap-checkboxes.png) + +Auto-snap does exactly what it sounds like: It automatically snaps two components together when you drag them near each other. This is handy for linking components together without having to explicitly link them (using the “link” button). This feature is turned on by default. If auto-snap is turned off, you can still initiate a “snap” by holding down the ALT/Option key on your keyboard during the drag. + +### Smart Insets + +Beside the “auto-snap” checkbox is another checkbox named “Smart Insets”. + +![Smart insets checkbox](/blog/gui-builder-improvements-3-7/guibuilder-2-smart-insets-auto-snap-checkboxes.png) + +Smart Insets is an experimental feature at this point. It uses some heuristics during a drag to try to determine how the insets should be linked. Currently the heuristics are quite basic (it tries to link to the nearest neighbour component in most cases), but we will be working on improving this for future releases. This feature is turned off by default while it is still being refined. The goal is to improve this to the point where it **always** makes the correct link choices – at which time you will be able to use the designer without having any knowledge of insets or reference components. It will **just work**. In the current version, I generally work with auto-snap “on”, and explicitly assign links myself using the “link” button. This gives me full control of my UI and how it will be resized. Once you get used to insets and how the links work, it becomes quite easy. + +### The Widget Control Pad + +![Widget control pad](/blog/gui-builder-improvements-3-7/guibuilder-2-widget-control-pad.png) + +When a component is selected, you should see a black floating panel appear in the lower right of the screen. + +This is the widget control pad, and it provides an alternative view of the component’s links. It also provides a useful list of incoming links (i.e. components that “depend on” this component’s positioning). In some cases, you may want to disconnect incoming links so that you can drag the component without affecting the position of dependent components. + +This control pad also includes game-pad-like controls (up, down, left, right), that allow you to “tab” the component to the next guide in that direction. Tab positions exist at component edges in the form. This is useful for aligning components with each other. + +### Keyboard Short-Cuts + + 1. **Arrow Keys** – Use the up/down/left/right arrow keys to nudge the currently selected component a little bit at a time. This is a convenient way to move the component to a position that is more precise than can easily be achieved with a mouse drag. + + 2. **Arrow Keys + SHIFT** – Hold down the SHIFT key while pressing an arrow key and it will “tab” the component to the next tab marker. The form has implicit tab markers at the edge of each component on the form. + + 3. **ALT/Option Key + Click or Drag** – Holding down the option/alt key while clicking or dragging a component will resulting in “snapping” behaviour even if auto-snap is turned off. + +### Sub-Containers + +In some cases, you may need to add sub-containers to your form to aid in grouping your components together. You can drag a container onto your form using the “Container” palette item (under “Core Components”). The default layout the subcontainer will be LayeredLayout so that you are able to position components within the sub-container with precision, just like on the root container. + +You can also change the layout of subcontainers to another classical layout manager (e.g. grid layout, box layout, etc..) and drag components directly into it just as you did with the old designer. This is very useful if parts of your form lend themselves. As an example, let’s drag a container onto the canvas that uses BoxLayout Y. (You can find this under the “Containers” section of the component palette). + +Drag the button (that was previously on the form) over that container, and you should see a drop-zone become highlighted. + +![Dropping container on child container with box layout y](/blog/gui-builder-improvements-3-7/guibuilder-2-subcontainer-add-child.png) + +You can drop the button directly there. You can As you drag more components into the sub-container, you’ll see them automatically laid out vertically. + +![Box Layout Y dropping 2nd child](/blog/gui-builder-improvements-3-7/guibuilder-2-subcontainer-add-child-2.png) + +### The Canvas Resize Tool + +When designing a UI with the new designer it is **very** important that you periodically test the form’s “resizing” behaviour so that you know how it will behave on different devices. Components may appear to be positioned correctly when the canvas is one size, but become out of whack when the container is resized. After nearly every manipulation you perform, it is good practice to drag the canvas resize tool (the button in the lower right corner of the designer) smaller and bigger so you can see how the positions are changed. If things grow out of whack, you may need to toggle an inset between fixed and auto, or add a link between some of the components so that the resizing behaviour matches your expectations. + +## The Future + +This GUI builder release represents the first step in a new direction. We have our own internal todo list for moving the GUI builder forward – things like improvements to Smart Insets, better styles integration, support for more component types, and better UI tools for manipulating component properties. But we’d like to hear your feedback. What are your pain points? What do you want to do with the GUI builder that you currently find difficult? Please let us know in the comments. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — June 28, 2017 at 9:53 pm ([permalink](https://www.codenameone.com/blog/gui-builder-improvements-3-7.html#comment-23358)) + +> I haven’t used this, so the answer might be obvious – when you use the new GUI builder, does this create a “GUI only” app ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-improvements-3-7.html) + + +### **Shai Almog** — June 29, 2017 at 3:30 am ([permalink](https://www.codenameone.com/blog/gui-builder-improvements-3-7.html#comment-23651)) + +> The GUI project is an old concept that was retired. +> +> The new GUI builder uses one form per GUI form. This means it works with regular Codename One projects and without the state machine. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-improvements-3-7.html) + + +### **salah Alhaddabi** — June 29, 2017 at 9:09 am ([permalink](https://www.codenameone.com/blog/gui-builder-improvements-3-7.html#comment-23594)) + +> Very nice. +> +> I would like to bring to your attention another tool that you might consider while you are improving your UI design tool as well. It is called Livecode (LC). In LC, you dont have to worry at all about positioning your UI with different screen resolutions and only one line of code makes all your UIs fit all screens. I wish CN1 has a similar ability since it is far more advanced that LC when it comes to technology integration. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-improvements-3-7.html) + + +### **Shai Almog** — June 29, 2017 at 12:59 pm ([permalink](https://www.codenameone.com/blog/gui-builder-improvements-3-7.html#comment-23662)) + +> Their tool is more about natural language not layout. It works with templates not components so it doesn’t allow you to do anything you want for any resolution or form factor (e.g. tablets). We would like to have more ready made templates that would effectively reduce the amount of UI you need to create. +> +> Also features like properties and the automatic UI generation API can go a long way here where you don’t need to write any UI code. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-improvements-3-7.html) + + +### **David G** — July 1, 2017 at 12:49 am ([permalink](https://www.codenameone.com/blog/gui-builder-improvements-3-7.html#comment-23668)) + +> Took the new GUI builder for a test run today and looks very promising, guys! Still some bugs to sort out (eg. the Tabs component was difficult to work with) but I’m sure you’re working on it. I can definitely see a business case for me signing up to CodeName one if the GUI builder reaches a point where I can quickly and reliably develop high quality front-ends for mobile devices. +> +> looking forward to future updates! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-improvements-3-7.html) + + +### **Shai Almog** — July 1, 2017 at 4:03 am ([permalink](https://www.codenameone.com/blog/gui-builder-improvements-3-7.html#comment-23581)) + +> Thanks! +> +> The tabs should be improved/fixed by now, we specifically didn’t commit that to keep the release stable. As I mentioned here: [https://www.codenameone.com…]() +> We’ll include that fix in the 3.7.2 update that will come our on Friday. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-improvements-3-7.html) + + +### **David G** — July 9, 2017 at 3:53 am ([permalink](https://www.codenameone.com/blog/gui-builder-improvements-3-7.html#comment-23685)) + +> Hi Shai, +> Thought I’d let you know I just downloaded the 3.7.2 pluggin for NetBeans and the GUI builder still doesn’t handle Tabs properly… there’s just nothing showing up in the navigation pane when components are added to a Tabs container. I was able to define tab text and icons but couldn’t go any further. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-improvements-3-7.html) + + +### **Shai Almog** — July 9, 2017 at 5:08 am ([permalink](https://www.codenameone.com/blog/gui-builder-improvements-3-7.html#comment-21470)) + +> Thanks. Can you please file an issue on that? +> It probably didn’t make it eventually, I recall seeing it on an internal list but it must have gotten buried. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-improvements-3-7.html) + + +### **Γιάννης Σαλταπίδας** — June 29, 2018 at 11:19 am ([permalink](https://www.codenameone.com/blog/gui-builder-improvements-3-7.html#comment-23819)) + +> Hello. There should be a tool to convert the style of the old GUI builder with the new GUI. Error free and smooth. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-improvements-3-7.html) + + +### **Shai Almog** — June 30, 2018 at 4:57 am ([permalink](https://www.codenameone.com/blog/gui-builder-improvements-3-7.html#comment-23831)) + +> Hi, +> tools become error free when people report errors in the issue tracker and we fix them: [http://github.com/codenameo…]() +> +> The converter is old so most people didn’t use it and just chose to start from scratch hence its still buggy. It’s probably not worth our time fixing a feature that people don’t report issues on. +> +> Regardless the converter was written for the original incarnation of the new GUI builder. The new GUI builder now includes the autolayout mode which is FAR superior to the previous approach. Since it’s so different conceptually from the old layout based approach there is no way to make it compatible or smooth. The converter will translate to the old approach which doesn’t give a huge advantage. +> +> I think our resources are better spent fixing issues in the devices/simulator. Improving the default UX and addressing issues people report in the issue tracker. Having said that if you run into an issue and report it in the issue tracker we’ll fix it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-improvements-3-7.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/gui-builder-walkthru.md b/docs/website/content/blog/gui-builder-walkthru.md new file mode 100644 index 0000000000..0cec27af28 --- /dev/null +++ b/docs/website/content/blog/gui-builder-walkthru.md @@ -0,0 +1,263 @@ +--- +title: GUI Builder Walkthru +slug: gui-builder-walkthru +url: /blog/gui-builder-walkthru/ +original_url: https://www.codenameone.com/blog/gui-builder-walkthru.html +aliases: +- /blog/gui-builder-walkthru.html +date: '2015-10-13' +author: Shai Almog +--- + +![Header Image](/blog/gui-builder-walkthru/new-gui-builder-preview.png) + +Since we announced the new GUI builder work we got quite a few questions in the discussion forum and offline +so I prepared a quick video showing how the new GUI builder will look when released (more or less). Notice that +a lot of things will change with the GUI builder but some things are pretty much fixed such as the basic architecture +with the XML to Java process. This is unlikely to change much. + +Some developers asked for samples of the XML and Java code the new GUI builder generates. +For your convenience this is the code for the demo above specifically the XML gui file is: + + + + + + + + + + + + + + + + + + +The Java code to match that is: + + + public class TestForm extends com.codename1.ui.Form { + public TestForm() { + this(com.codename1.ui.util.Resources.getGlobalResources()); + } + + public TestForm(com.codename1.ui.util.Resources resourceObjectInstance) { + initGuiBuilderComponents(resourceObjectInstance); + } + + //-- DON'T EDIT BELOW THIS LINE!!! + private com.codename1.ui.TextField gui_Text_Field_1 = new com.codename1.ui.TextField(); + private com.codename1.ui.Label gui_Label_1 = new com.codename1.ui.Label(); + private com.codename1.ui.Container gui_Container_1 = new com.codename1.ui.Container(new com.codename1.ui.layouts.FlowLayout()); + private com.codename1.ui.Button gui_Button_2 = new com.codename1.ui.Button(); + private com.codename1.ui.Button gui_Button_1 = new com.codename1.ui.Button(); + + // + private void guiBuilderBindComponentListeners() { + EventCallbackClass callback = new EventCallbackClass(); + gui_Button_1.addActionListener(callback); + } + + class EventCallbackClass implements com.codename1.ui.events.ActionListener, com.codename1.ui.events.DataChangedListener { + private com.codename1.ui.Component cmp; + public EventCallbackClass(com.codename1.ui.Component cmp) { + this.cmp = cmp; + } + + public EventCallbackClass() { + } + + public void actionPerformed(com.codename1.ui.events.ActionEvent ev) { + if(ev.getSource() == gui_Button_1) { + onButton_1ActionEvent(ev); + } + } + + public void dataChanged(int type, int index) { + } + } + private void initGuiBuilderComponents(com.codename1.ui.util.Resources resourceObjectInstance) { + guiBuilderBindComponentListeners(); + setLayout(new com.codename1.ui.layouts.BoxLayout(com.codename1.ui.layouts.BoxLayout.Y_AXIS)); + setTitle("TestForm"); + setName("TestForm"); + addComponent(gui_Text_Field_1); + addComponent(gui_Label_1); + addComponent(gui_Container_1); + gui_Container_1.setName("Container_1"); + gui_Container_1.addComponent(gui_Button_2); + gui_Button_2.setText("This Button"); + gui_Button_2.setName("Button_2"); + addComponent(gui_Button_1); + gui_Text_Field_1.setText("TextField"); + gui_Text_Field_1.setName("Text_Field_1"); + gui_Label_1.setText("Label"); + gui_Label_1.setName("Label_1"); + gui_Container_1.setName("Container_1"); + gui_Button_1.setText("Hi World"); + gui_Button_1.setName("Button_1"); + }// + + //-- DON'T EDIT ABOVE THIS LINE!!! + public void onButton_1ActionEvent(com.codename1.ui.events.ActionEvent ev) { + Dialog.show("Hi", "Hi world: " + gui_Text_Field_1.getText(), "OK", null); + } + } +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Clement Levallois** — October 15, 2015 at 6:07 am ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-21486)) + +> Clement Levallois says: +> +> hello, +> great stuff as usual. May I suggest that the workflow allows for a “all without coding” route? Your demo showed that 2 lines of code had to be added when a new “GUi form” was created, in order to make it displayed. A tick box in the wizard at the moment of Form creation could do it. +> Essentially, it is key to allow beginners to use the designer much before they have to write even one line of code, as is the case now. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **Shai Almog** — October 15, 2015 at 6:39 am ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-22502)) + +> Shai Almog says: +> +> Good point. We should have some better project templates, ideally with ready made projects that already include some forms. +> We did that with the old designer (e.g. with the Tabs based application) but it wasn’t used much so we need to get more refined use cases for this. +> +> Right now I’d like to stabilize the designer so we can start building on top of it both tutorials and things such as this. At the moment this is somewhat of a regression for a “no coding” approach since some things like navigating from one form to the next aren’t supported in the new GUI builder. Naturally, we want to fix that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **mtran** — October 16, 2015 at 2:49 pm ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-21479)) + +> mtran says: +> +> Where can I download the Gui Buider ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **Shai Almog** — October 17, 2015 at 4:31 am ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-22142)) + +> Shai Almog says: +> +> It will be a part of the next plugin update early next week. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **Jeremy** — October 18, 2015 at 2:38 pm ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-24193)) + +> Jeremy says: +> +> Good job, but I think it would even be better if the Gui builder is designed such that it is possible to switch between the drag and drop style and the XML layout. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **Shai Almog** — October 19, 2015 at 2:17 am ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-22341)) + +> Shai Almog says: +> +> Thanks for the feedback. +> As you can see above the XML syntax wasn’t designed for human consumption as much as it was designed for accuracy. So editing this will be less intuitive. +> You can edit this XML thru NetBeans and also use it to find out what happened if something went wrong. I think its a better approach since NetBeans already has great XML editing capabilities. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **Chidiebere Okwudire** — October 29, 2015 at 3:48 pm ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-22511)) + +> Chidiebere Okwudire says: +> +> Hi Shai, +> +> I like what I see in the video. One thing that’s still unclear to me is what will eventually happen to the navigation logic that is present in the current GUI builder. Can you say something about that? Basically, how is navigation envisaged to work in the new GUI builder *especially* for scenarios where some forms are completely handcoded whereas others are created using the GUI builder? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **Shai Almog** — October 30, 2015 at 5:04 am ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-22254)) + +> Shai Almog says: +> +> Hi, +> in the new GUI builder each form/container lives in isolation which is similar to the way traditional Java GUI builders have always worked. +> The migration wizard we just introduced generates a fake state machine that just moves you between form instances. +> +> Because of that the new GUI builder is more like a handcoded app than a GUI builder app. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **bledi** — October 31, 2015 at 4:52 pm ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-22495)) + +> bledi says: +> +> Hello, +> i just downloaded the last version of the netbenas plugin and there seems not te be a new gui builder. When are you planning to relase the new one, as ti seems very promissing. Thank you +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **Shai Almog** — November 1, 2015 at 4:27 am ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-22437)) + +> Shai Almog says: +> +> Hi, +> Where did you download it from and what’s the version. 3.2.2 is the latest version of the NetBeans plugin. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **bledi** — November 1, 2015 at 11:01 am ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-21487)) + +> bledi says: +> +> I installed again from the netbeans plugins and now i have 3.2.2. On all newly created project i cannot add events to buttons etc. On already existing projects it works as before. There is a thread in the google group for this also. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **Dan** — November 5, 2015 at 3:16 am ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-22267)) + +> Dan says: +> +> Thanks for this overview, Shai – and thanks for including it in the latest CodenameOne release. Downloaded it today and have started playing with it. Thanks for the tip about the XML file – for some reason, dragging and dropping a textfield (for me at least) kept it as type “Label”. so if i go into the XML and change the type to “TextField” it seems to come out ok. Keep up the good work! – dan +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **Shai Almog** — November 6, 2015 at 4:26 am ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-22438)) + +> Shai Almog says: +> +> Hi, +> thanks for the feedback. We are making heavy changes to the tool as we speak to get it to alpha level. Our focus in the technology preview was on the concept and the XML process with back and forth communication to the IDE. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + + +### **Yaakov Gesher** — November 8, 2015 at 7:28 am ([permalink](https://www.codenameone.com/blog/gui-builder-walkthru.html#comment-22530)) + +> Yaakov Gesher says: +> +> Hi, I just converted an existing project using the migration wizard, and in all the generated files the NetBeans shows me compilation errors: Cannot find symbol ‘setGlobalResources’ in class ‘Resources’. After refreshing project libraries, the errors all went away. Just in case anyone else runs into the same issue! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgui-builder-walkthru.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/gzip-support.md b/docs/website/content/blog/gzip-support.md new file mode 100644 index 0000000000..686b262050 --- /dev/null +++ b/docs/website/content/blog/gzip-support.md @@ -0,0 +1,92 @@ +--- +title: GZip Support +slug: gzip-support +url: /blog/gzip-support/ +original_url: https://www.codenameone.com/blog/gzip-support.html +aliases: +- /blog/gzip-support.html +date: '2013-06-16' +author: Shai Almog +--- + +![Header Image](/blog/gzip-support/gzip-support-1.png) + + + + + +![Zip](/blog/gzip-support/gzip-support-1.png) + + + + +We now have new support for GZipInputStream and GZipOutputStream thanks to the great work done by the guys in the +[ +JZLib +](https://github.com/ymnk/jzlib) +project, we ported their work into the project class hierarchy and added a GZConnectionRequest which will automatically unzip an HTTP response if it is indeed gzipped. + + +By default this class doesn’t request gzipped data but its pretty easy to do so just add the HTTP header + +Accept-Encoding: gzip e.g.: + +GZConnectionRequest con = new GZConnectionRequest(); + + +con. + +addRequestHeader(“Accept-Encoding”, “gzip”); + + +Do the rest as usual and you should have smaller responses by potential. + + +We thought about adding this capability to the global ConnectionRequest but eventually decided not to do so since it will increase the size of the distribution to everyone. If you do not need the gzip functionality the obfuscator will just strip it out during the compile process. + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — June 17, 2013 at 8:31 am ([permalink](https://www.codenameone.com/blog/gzip-support.html#comment-21691)) + +> Anonymous says: +> +> This is great news ! I will update my blog post about compression with this, keep up the good work ! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgzip-support.html) + + +### **Anonymous** — February 6, 2014 at 5:47 am ([permalink](https://www.codenameone.com/blog/gzip-support.html#comment-21434)) + +> Anonymous says: +> +> Is it also supported on the WebBrowser component when fetching HTML? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgzip-support.html) + + +### **Anonymous** — February 7, 2014 at 3:13 am ([permalink](https://www.codenameone.com/blog/gzip-support.html#comment-21767)) + +> Anonymous says: +> +> Since the web browser uses native connections and doesn’t go thru connection request gzip should “just work” for that case. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fgzip-support.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/hamburger-sidemenu.md b/docs/website/content/blog/hamburger-sidemenu.md new file mode 100644 index 0000000000..c6e2cb3a83 --- /dev/null +++ b/docs/website/content/blog/hamburger-sidemenu.md @@ -0,0 +1,244 @@ +--- +title: Hamburger Sidemenu +slug: hamburger-sidemenu +url: /blog/hamburger-sidemenu/ +original_url: https://www.codenameone.com/blog/hamburger-sidemenu.html +aliases: +- /blog/hamburger-sidemenu.html +date: '2013-02-26' +author: Shai Almog +--- + +![Header Image](/blog/hamburger-sidemenu/hqdefault.jpg) + + + +The title of this post might be a bit misleading… Hamburger? + + +The Hambuger sidemenu is the menu style popularized by the Facebook app, its called a Hamburger because of the 3 line icon on the top left resembling a hamburger patty between two buns (get it: its a side menu…)! + + + +Up until now these things were a pain to implement smoothly in Codename One, but Chen wouldn’t let this rest and just committed support for this feature. Working with a Hamburger menu couldn’t be simpler! Just set the command behavior to side menu (in the Display class) and it just works. You can also set it by setting the commandBehavior theme constant in the + +Codename One designer to “Side”. + + +Then just add commands and watch them make their way into the side menu allowing you to build any sort of navigation you desire. + + +Chen updated the Facebook demo to show this off, its still only available via SVN and requires the latest SVN version of Codename One for all the bells and whistles to function properly but it already looks pretty sweet! + + +Now all we need is a cheeseburger sidemenu with fries. + + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — February 28, 2013 at 7:21 pm ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-21664)) + +> Anonymous says: +> +> Thanks Chen, was hoping that would land for 1.1 – looks great! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Anonymous** — March 1, 2013 at 6:37 am ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-21915)) + +> Anonymous says: +> +> Great job Chen!! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Anonymous** — August 17, 2013 at 4:36 pm ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-21666)) + +> Anonymous says: +> +> This looks great, but I have no idea how to use it. Unfortunately, as a total beginner, ” Just set the command behavior to side menu (in the Display class)” does not mean anything to me yet, and i dont know how to setup the menus on the left to start with. There is a “Commands” Properties in the editor, but when you hit Add, and enter “side menu” as the “name” attribute, it doesnt seen to do anything. +> +> Has anyone got a link to a demo handy? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Anonymous** — August 18, 2013 at 1:34 am ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-21917)) + +> Anonymous says: +> +> Thanks, its sometimes hard to see where we are being obtuse. The facebook demo shows the side menu. +> +> To activate command behavior either: +> +> Open the designer, select the theme. Go to the constants tab, click “Add” and select commandBehavior from the combo box, type in Side for the value. +> +> Or use: +> +> Display.getInstance().setCommandBehavior(Display.COMMAND_BEHAVIOR_SIDE_NAVIGATION); +> +> Commands are either added by clicking the Command section in the form in the GUI designer and adding commands or by invoking the method on form called addCommand. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Anonymous** — August 18, 2013 at 7:20 am ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-21811)) + +> Anonymous says: +> +> Magic – works! Added in the designer. Worked with latest eclipse plugin, no SVN pull required. CN1 is amazing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **George Njoroge** — September 4, 2015 at 9:29 am ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-22218)) + +> George Njoroge says: +> +> Can I get a link project source code +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Shai Almog** — September 5, 2015 at 3:58 am ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-22340)) + +> Shai Almog says: +> +> Its in our demos repository [http://github.com/codenameo…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Bertrand Gauvreau** — October 16, 2015 at 3:52 pm ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-22442)) + +> Bertrand Gauvreau says: +> +> I Shai ! First, Thank you for offering us CodenameOne ! It’s a fantastic tool ! +> I have an issue with the hamburger menu. When I run my app on my Android device and click on the hamburger menu icon, the menu opens but it slides up with the whole window and makes the Action Bar disappear. The action bar reappears only when I restart the app. +> Do you have any idea ? +> Thank You +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Shai Almog** — October 17, 2015 at 4:33 am ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-22367)) + +> Shai Almog says: +> +> Great to hear! +> Did you update the theme constant to side? +> +> I would suggest you migrate to the new Toolbar API which is more powerful than the side menu on its own and encapsulates all its functionality. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Bertrand Gauvreau** — October 17, 2015 at 12:46 pm ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-24182)) + +> Bertrand Gauvreau says: +> +> Thank you Shai +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Mahmoud** — March 26, 2016 at 8:43 pm ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-22701)) + +> Mahmoud says: +> +> Dear Shai, +> i have menu and my background is white but i have gradient line at the first of menu +> how i can remove it +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Shai Almog** — March 27, 2016 at 4:26 am ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-21503)) + +> Shai Almog says: +> +> That’s the shadow for the sidemenu set the theme constant sideMenuShadowBool=false +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Mahmoud** — March 27, 2016 at 5:43 am ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-24203)) + +> Mahmoud says: +> +> Thanks Shai 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Akinniranye James** — September 14, 2016 at 1:39 pm ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-22559)) + +> Akinniranye James says: +> +> Is it possible to achieve a side menu as rich as this? Since we cant even set different uiids for commands. Am considering using layered pane layout +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Shai Almog** — September 15, 2016 at 3:47 am ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-22762)) + +> Shai Almog says: +> +> This is the side menu in the up to date kitchen sink. You can customize the Commands heavily but it’s far more intuitive to use the Toolbar API… +> +> [https://uploads.disquscdn.c…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Akinniranye James** — September 15, 2016 at 8:01 pm ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-21458)) + +> Akinniranye James says: +> +> Wow, I barely recognize this Kitchen Sink, wow. Good job. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Akinniranye James** — September 15, 2016 at 8:26 pm ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-21823)) + +> Akinniranye James says: +> +> My bad. I never knew there is toolbar..addComponentToSideMenu, I have only been using toolbar.addCommandToSideMenu +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **tracey-de santa** — July 26, 2017 at 6:21 am ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-23538)) + +> tracey-de santa says: +> +> cool, +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + + +### **Akinniranye James** — July 26, 2017 at 3:59 pm ([permalink](https://www.codenameone.com/blog/hamburger-sidemenu.html#comment-23253)) + +> Akinniranye James says: +> +> check out our app [https://play.google.com/sto…](). +> using codenameone +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhamburger-sidemenu.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/handling-the-exception.md b/docs/website/content/blog/handling-the-exception.md new file mode 100644 index 0000000000..14ad04266c --- /dev/null +++ b/docs/website/content/blog/handling-the-exception.md @@ -0,0 +1,72 @@ +--- +title: Handling The Exception +slug: handling-the-exception +url: /blog/handling-the-exception/ +original_url: https://www.codenameone.com/blog/handling-the-exception.html +aliases: +- /blog/handling-the-exception.html +date: '2013-07-07' +author: Shai Almog +--- + +![Header Image](/blog/handling-the-exception/handling-the-exception-1.png) + + + + +[ +![Exception](/blog/handling-the-exception/handling-the-exception-1.png) +](/img/blog/old_posts/handling-the-exception-large-2.png) + + + +Handling errors or exceptions in a deployed product is pretty difficult, most users would just throw away your app and some would give it a negative rating without providing you with the opportunity to actually fix the bug that might have happened. + + +Google improved on this a bit by allowing users to submit stack traces for failures on Android devices but this requires the users approval for sending personal data which you might not need if you only want to receive the stack trace and maybe some basic application state (without violating user privacy). + + +For quite some time Codename One had a very powerful feature that allows you to both catch and report such errors, the error reporting feature uses the Codename One cloud which is exclusive for pro/enterprise users. Normally in Codename One we catch all exceptions on the EDT (which is where most exceptions occur) and just display an error to the user + +as you can see in the picture. Unfortunately this isn’t very helpful to us as developers who really want to see the stack, furthermore we might prefer the user doesn’t see an error message at all! + + +Codename One allows us to grab all exceptions that occur on the EDT and handle them using the method + +addEdtErrorHandler in the Display class. Adding this to the Log’s ability to report errors directly to us and we can get a very powerful tool that will send us an email with information when a crash occurs! + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — April 5, 2016 at 9:51 pm ([permalink](https://www.codenameone.com/blog/handling-the-exception.html#comment-21483)) + +> Chidiebere Okwudire says: +> +> Is it possible to send log to another email address than the developer’s? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhandling-the-exception.html) + + +### **Shai Almog** — April 6, 2016 at 2:41 am ([permalink](https://www.codenameone.com/blog/handling-the-exception.html#comment-22447)) + +> Shai Almog says: +> +> No. A lot of features are locked directly to that email account. +> It’s a problem to accept an email dynamically for some services as they might be handled in complex ways e.g. sending an email from a production app. So it’s important to us that one valid email is used and that an email is used per developer to avoid abuse. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhandling-the-exception.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/hands-on-with-the-blackberry-tools-on-the-z10.md b/docs/website/content/blog/hands-on-with-the-blackberry-tools-on-the-z10.md new file mode 100644 index 0000000000..d5a32b692e --- /dev/null +++ b/docs/website/content/blog/hands-on-with-the-blackberry-tools-on-the-z10.md @@ -0,0 +1,198 @@ +--- +title: Hands-on With The Blackberry Tools On The Z10 +slug: hands-on-with-the-blackberry-tools-on-the-z10 +url: /blog/hands-on-with-the-blackberry-tools-on-the-z10/ +original_url: https://www.codenameone.com/blog/hands-on-with-the-blackberry-tools-on-the-z10.html +aliases: +- /blog/hands-on-with-the-blackberry-tools-on-the-z10.html +date: '2013-06-23' +author: Shai Almog +--- + +![Header Image](/blog/hands-on-with-the-blackberry-tools-on-the-z10/hands-on-with-the-blackberry-tools-on-the-z10-1.jpg) + + + + +[ +![Picture](/blog/hands-on-with-the-blackberry-tools-on-the-z10/hands-on-with-the-blackberry-tools-on-the-z10-1.jpg) +](/img/blog/old_posts/hands-on-with-the-blackberry-tools-on-the-z10-large-2.jpg) + + + +Note: skip to the bottom for some instructions on working with the BB Z10. + + + + + + +Lately we’ve been asked by one of our pro customers to fix some issues which occurred only on the z10 device. I thought this would be an easy task: just grab the tools from the blackberry site and then use them to debug the issue. I was quite wrong… Apparently the emulator can only run in a virtualization environment. + + + + +OK that shouldn’t stop me, I grabbed the VMPlayer installed it then installed the BB emulator and had myself a running emulator… Or at least I should have been so lucky! My machine couldn’t run it because the display driver wasn’t supported, took me a while to figure this one out. I tried on another PC instead and was luckier, it worked I had a emulator running. + + +Blackberry 10 is in many regards more like Android than older blackberries. So it doesn’t support our existing BB apps, however it does support running Android apps if they are packaged specifically for it. + + +So I started working on + +installing the android build of the app, should be an easy task, right? + + + +Wrong again. Spent a couple of hours understanding the process of converting the .apk to a .bar file and then the signing process. Finally I, got a valid .bar file and installing it wasn’t hard. The app was finally running in the emulator and I got a tingling happy feeling all over. + + + + +Then the app crashed which was pretty much what our customer complained about, so lets take a look at the log or console. Should be somewhere, right? + + + + +Wrong, you need an ssh client to connect to the VM and then look for the file somewhere… That’s inconvenient but doable, I really wanted to know what the hell happened. + + + + +Launching Putty and connecting to get the log then finding the path, trying to get in and it seems that I don’t have permissions to enter the directory for the log. Well that broke me, how do they expect anyone to develop apps for this? + + + + +Some more googling and I came to the conclusion that the only way to debug this is with a device. + + + +Well a few days past and I got myself a limited edition z10 device (thanks to +[ +Shai Ifrach +](https://twitter.com/future_soft/) +), seems like it became a hit device because it’s a limited edition. It even sold for $1799 – +[ +http://www.ebay.com/itm/Developer-BlackBerry-Z10-Limited-Edition-Red-/321094687957 +](http://www.ebay.com/itm/Developer-BlackBerry-Z10-Limited-Edition-Red-/321094687957) + +Checking the problem on the device should be easier, it seemed that the OS version on the device was out of date and since they push the OS updates through the carrier this posed a problem. + + +Or am I? After + +some more googling I found a manual hacking process to manually update the OS. Got the approval from the owner (I didn’t think I could hack a $1799 loaner device without that) and I was able to update the z10 OS, now lets see what’s going on. + + + + +After some more research it seems like the easiest way would be to use the eclipse plugin with the device, grabbed the plugin some more setups and got it working and I’m getting the output in the ddms, now finally I managed to debug the issue and to figure out what was the problem. + + +In + +conclusion – Blackberry… Please… show some love for developers, if it’s not practical to develop properly with the emulator don’t ship it and I thought your JDE was awful. + + + +The device itself is surprisingly decent, it feels like they have a slim chance to maintain some market with this hardware. + +For those of you who want to build apps for Blackberry OS 10, you need to start with your Android APK (send an Android build in Codename One) then converting the apk to a bar file which can be done in a few ways: + + 1. Online tool – Blackberry provides an applet on their site where you provide the apk and the signing certs and it allows you to convert and sign your apk file. + 2. Command line tools – a few script files that will allow you to preform the conversion in command line + 3. Eclipse plugin – through the plugin you can do the conversion. + + + +See also – +[ +http://developer.blackberry.com/android/tools/ +](http://developer.blackberry.com/android/tools/) + +We would like to simplify this process for our developers but we are running into some issues with the Blackberry command line tools and their signing process. It seems signatures aren’t stored in any standard way. + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — June 25, 2013 at 4:57 pm ([permalink](https://www.codenameone.com/blog/hands-on-with-the-blackberry-tools-on-the-z10.html#comment-21879)) + +> Anonymous says: +> +> i hope that RIM can help you more that some time in the future codename one will support B10 devices by default. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhands-on-with-the-blackberry-tools-on-the-z10.html) + + +### **Anonymous** — July 2, 2013 at 7:32 am ([permalink](https://www.codenameone.com/blog/hands-on-with-the-blackberry-tools-on-the-z10.html#comment-21870)) + +> Anonymous says: +> +> I wonder what they were thinking, making development so difficult for their OS, knowing fully well it’s not the best OS or even Hardware in the market. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhands-on-with-the-blackberry-tools-on-the-z10.html) + + +### **Anonymous** — July 4, 2013 at 5:19 pm ([permalink](https://www.codenameone.com/blog/hands-on-with-the-blackberry-tools-on-the-z10.html#comment-21756)) + +> Anonymous says: +> +> Their dev tools were never a pleasant experience, the JDE was also painful but workable. +> +> The current simulator is a tool for hackers only, but can you blame them? they don’t have much time and the pressure on them is huge, I hope they will improve over time. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhands-on-with-the-blackberry-tools-on-the-z10.html) + + +### **Anonymous** — January 31, 2014 at 3:47 am ([permalink](https://www.codenameone.com/blog/hands-on-with-the-blackberry-tools-on-the-z10.html#comment-21672)) + +> Anonymous says: +> +> where is the online converter can you give me a link? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhands-on-with-the-blackberry-tools-on-the-z10.html) + + +### **Anonymous** — January 31, 2014 at 4:39 am ([permalink](https://www.codenameone.com/blog/hands-on-with-the-blackberry-tools-on-the-z10.html#comment-21954)) + +> Anonymous says: +> +> They change the URL’s all the time in the RIM site. Did you try googling? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhands-on-with-the-blackberry-tools-on-the-z10.html) + + +### **Anonymous** — January 31, 2014 at 5:40 am ([permalink](https://www.codenameone.com/blog/hands-on-with-the-blackberry-tools-on-the-z10.html#comment-22002)) + +> Anonymous says: +> +> yeh i think they removed it… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhands-on-with-the-blackberry-tools-on-the-z10.html) + + +### **Anonymous** — May 1, 2014 at 4:24 am ([permalink](https://www.codenameone.com/blog/hands-on-with-the-blackberry-tools-on-the-z10.html#comment-22086)) + +> Anonymous says: +> +> Energy, thank you that we find a simple and powerfull solution to build for BB10 and thanks that rim makes it pleasant for developers to build for their OS, appreciate it. amen. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhands-on-with-the-blackberry-tools-on-the-z10.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/happy-new-year-looking-back-forward.md b/docs/website/content/blog/happy-new-year-looking-back-forward.md new file mode 100644 index 0000000000..9b90e08282 --- /dev/null +++ b/docs/website/content/blog/happy-new-year-looking-back-forward.md @@ -0,0 +1,132 @@ +--- +title: Happy New Year – Looking Back & Forward +slug: happy-new-year-looking-back-forward +url: /blog/happy-new-year-looking-back-forward/ +original_url: https://www.codenameone.com/blog/happy-new-year-looking-back-forward.html +aliases: +- /blog/happy-new-year-looking-back-forward.html +date: '2014-12-30' +author: Shai Almog +--- + +![Header Image](/blog/happy-new-year-looking-back-forward/happy-new-year-looking-back-forward-1.png) + + + + + +![Picture](/blog/happy-new-year-looking-back-forward/happy-new-year-looking-back-forward-1.png) + + + + + + + + + + + + + + + + +We are closing 2014 which has been a pretty eventful year for us where we finally solidified Codename One, looking into 2015 we have a lot of great plans ahead! + +The new year seems like a great time to discuss some of our short/long term plans for Codename One as we move forward and our general thoughts. But first I’d like to open with the things we did badly in 2014 and that we should probably improve in 2015: + + 1. We didn’t release Codename One 3.0 (or 2.5 for that matter). We were so busy with everything that making a stable release got sidetracked. This is something we need to invest more time into! + 2. We spent too much focus on big things (new VM, new windows phone pipeline, corporate server) and too little time on small but crucial features. Some of those features were crucial, but speaking to developers it seems most would prefer many small increments to large revolutions. + 3. We didn’t invest in design – our themes didn’t see any major change since launch. We need to significantly overhaul that. + 4. We didn’t capitalize on some features, e.g. we built new graphics pipelines and didn’t really use the functionality for charts, improved transition etc. + + 5. We traveled too much in 2014, while it seemed productive initially it didn’t directly map to business success and we probably won’t be doing as much travel/conferences in 2015. + +We hope to improve on all of those for 2015 and so far its looking very positive. Most of the “heavy” infrastructure work was done in 2014 which means 2015 will allow us to leap forward with better underlying technology and focus on the surface of things. + +These are the things we’re very happy about in 2014: + + + + + + + + 1. Community cn1lib’s – these started taking off really well! Some great work from many different members of the community as well as a few of our own. I think we will focus on bringing out far more features as cn1libs rather than integrate them in the core. At least initially. + 2. The infrastructure work such as improving the build servers, replacing the VM and the rendering pipelines. It was painful and time consuming to do all this work but it is already proving its value. + 3. We are very happy with the new Toolbar API and hope to do similar convenience API’s in 2015 + 4. Our presentation and videos have improved significantly, but we didn’t do nearly as much video tutorials as we should have. + + 5. Pretty great applications from community members e.g. +[ +Travel2gether +](http://codenameone.com/featured-travel2gether.html) +, +[ +yhomework +](http://www.codenameone.com/featured-yhomework.html) +etc. + + + + + + + + + +For 2015 our high level goals are: + + + + * Refinement – We want to make the process of signing up to Codename One, creating an app, paying etc. far more refined and smooth. + + * Enterprise functionality – most of the features in Codename One are in the lower grade subscription levels. We are now focused on adding more high end features. + * Integrations – we are looking to support the top mobile solutions out of the box, so you don’t have to do the integration on your own. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/helpbutton-component.md b/docs/website/content/blog/helpbutton-component.md new file mode 100644 index 0000000000..0a584f8b2b --- /dev/null +++ b/docs/website/content/blog/helpbutton-component.md @@ -0,0 +1,44 @@ +--- +title: HELPBUTTON COMPONENT +slug: helpbutton-component +url: /blog/helpbutton-component/ +original_url: https://www.codenameone.com/blog/helpbutton-component.html +aliases: +- /blog/helpbutton-component.html +date: '2020-10-31' +author: Steve Hannah +--- + +This is the second is a series of blog posts hightlighting some of the components available in the CodeRAD cn1lib. The [first post (or series of posts) introduced the RAD Chatroom component](https://www.codenameone.com/blog/rad-chatroom-part-1.html), a rich 2nd order UI component that encapsulates the user interface for a fully functional chat room. + +__ | A second-order UI component is a complex UI component, usually composed of multiple basic components, which is designed for a specific type of application. Some examples of second-order UI components are login forms, contacts lists, chat room components, news lists, etc.. +---|--- + +In this post I share a much simpler, first-order component: The [HelpButton](https://shannah.github.io/CodeRAD/javadoc/ca/weblite/shared/components/HelpButton.html). The HelpButton is just a button that displays a “Help” or “Error” icon. When the user clicks on this button, it pops up with some “help” text. + +![](/blog/helpbutton-component/help-button-animated.gif) + +### Usage Example + +The following is the snippet that was used to generate the above screen capture: + + + Form hi = new Form("Hi World", BoxLayout.y()); + HelpButton btn = new HelpButton("This is some help text to give you some hints"); + hi.add(FlowLayout.encloseIn(new Label("Hi World"), btn)); + hi.show(); + +There really isn’t much to this component, but it is a handy addition to the toolbox nonetheless. + +| To use the HelpButton component you’ll need to add the CodeRAD cn1lib to your project, which is available in through Codename One preferences. For instructions on adding cn1libs to your projects, see [this tutorial](https://www.beta.codenameone.com/blog/automatically-install-update-distribute-cn1libs-extensions.html). +---|--- + +For more information about CodeRAD, check out its [github repo](https://github.com/shannah/CodeRAD). + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/hiding-url-security-advocacy.md b/docs/website/content/blog/hiding-url-security-advocacy.md new file mode 100644 index 0000000000..b939951d20 --- /dev/null +++ b/docs/website/content/blog/hiding-url-security-advocacy.md @@ -0,0 +1,79 @@ +--- +title: Hiding, URL Security & Advocacy +slug: hiding-url-security-advocacy +url: /blog/hiding-url-security-advocacy/ +original_url: https://www.codenameone.com/blog/hiding-url-security-advocacy.html +aliases: +- /blog/hiding-url-security-advocacy.html +date: '2015-11-08' +author: Shai Almog +--- + +![Header Image](/blog/hiding-url-security-advocacy/hiding-security-advocacy.png) + +A common trick for animating Components in Codename One is to set their preferred size to 0 and then invoke +`animateLayout()` thus triggering an animation to hide said component. There are several issues +with this trick but one of the biggest ones is the fact that `setPreferredSize` has been deprecated +for quite a while. + +We recently added a `setHidden`/`isHidden` method pair that effectively encapsulates +this functionality and a bit more. This shouldn’t be confused with `setVisible`/`isVisible` +that just toggle the visibility of the component. +One of the issues `setHidden` tries to solve is the fact that preferred size doesn’t include the margin +in the total and thus a component might still occupy space despite being hidden. To solve this the margin is set to 0 +when hiding and restored to its original value when showing the component again by resetting the UIID +(which resets all style modifications). +This functionality might be undesired which is why we have a version of the `setHidden` method that +accepts a boolean flag indicating whether the margin/UIID should be manipulated. You can effectively +hide/show a component without deprecated code using something like this: + + + Button toHide = new Button("Will Be Hidden"); + Button hide = new Button("Hide It"); + hide.addActionListener((e) -> { + hide.setEnabled(false); + boolean t = !toHide.isHidden(); + toHide.setHidden(t); + toHide.getParent().animateLayoutAndWait(200); + toHide.setVisible(t); + hide.setEnabled(true); + }); + +Notice that in the first/last lines of the event processing I block the button from getting additional events. Since +the code is sequential this works rather well and the button won’t get duplicate events during the animation. +Codename One currently doesn’t support concurrent animations so its up to you as a developer to serialize +your animation requests in the framework. + +#### Accessing Insecure URL’s In iOS 9 + +Due to recent security exploits Apple blocked some access to insecure URL’s which means that http code that +worked before might stop working for you on iOS 9. This is generally a good move, you should use https and +avoid http as much as possible but that’s sometimes impractical especially when working with an internal +or debug environment (setting up SSL is a pain). + +We considered adding the required build hints by default but it seems that Apple will reject your app if you just +include that and don’t have a good reason. We could have done it for debug only but then people might have +run into it in production. +The solution at the moment is to use the venerable `ios.plistInject` build hint and set it to: +`NSAppTransportSecurityNSAllowsArbitraryLoads` +Read more about this in [the discussion forum post](https://groups.google.com/d/msg/codenameone-discussions/5jrBWjgcarM/Q5z28PsrEgAJ). + +#### New Advocacy Group + +We’ve posted about this to the discussion forum but if you subscribe via email it might have gotten buried. +If you want to help Codename one and its related 3rd party projects by contributing at most 5 minutes per +day please join [this group](https://groups.google.com/forum/#!forum/codename-one-advocacy). +Thru this group we (and you if you have a Codename One relevant project such as an advocacy site, tutorial, +library or blog post) can post links and ask for social help: e.g. upvote, like, share, retweet, etc. + +With social networks its pretty hard to get your voice out as people get drowned with messaging from all directions. +In this way we can both help you guys to get noticed by the community at large and you can help us to spread +our message further thru social clout. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/how-do-i.md b/docs/website/content/blog/how-do-i.md new file mode 100644 index 0000000000..d54b6056e5 --- /dev/null +++ b/docs/website/content/blog/how-do-i.md @@ -0,0 +1,34 @@ +--- +title: How Do I??? +slug: how-do-i +url: /blog/how-do-i/ +original_url: https://www.codenameone.com/blog/how-do-i.html +aliases: +- /blog/how-do-i.html +date: '2013-01-08' +author: Shai Almog +--- + +![Header Image](/blog/how-do-i/hqdefault.jpg) + + + +Answering common question is what a FAQ is usually for, but usually that’s just not enough. A common presentation tip is: “Show, don’t tell”. + +Which is why we launched the +[ +“How Do I?” +](http://www.codenameone.com/how-do-i.html) +section in the Codename One website, this section contains short video tutorials demonstrating how to do small things in Codename One from creating your first Codename One application to monetizing and debugging it (upcoming). + +We hope to flesh out this section with more videos as time goes on, feel free to ask for future videos right here. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/how-does-it-work.md b/docs/website/content/blog/how-does-it-work.md new file mode 100644 index 0000000000..8a5d9496db --- /dev/null +++ b/docs/website/content/blog/how-does-it-work.md @@ -0,0 +1,216 @@ +--- +title: How does it Work? +slug: how-does-it-work +url: /blog/how-does-it-work/ +original_url: https://www.codenameone.com/blog/how-does-it-work.html +aliases: +- /blog/how-does-it-work.html +date: '2017-06-22' +author: Shai Almog +--- + +![Header Image](/blog/how-does-it-work/build-real-world-full-stack-mobile-apps-in-java.jpg) + +You know that feeling before going on stage to talk or perform. It’s a knot in your stomach but also an exhilarating sense of excitement about what’s to come…​ I’ve got that fidgety feeling of “can’t wait to get it out” and yet I feel there is so much more to do. + +Thanks for all the comments, questions, suggestions & votes for the [last couple of posts](/blog/good-to-great.html). Those always help tremendously! +One of our bootcamp participants mentioned the length of my videos in the bootcamp and my response at the time was that I can’t possibly make the videos shorter as it would be far more work…​ + +Turns out that this isn’t the case. It was just the problematic tools I was using. Once I got the flow of video making, splitting the videos to shorter more concise videos became easier. Newer videos within the course are much shorter but include roughly the same amount of information. That information density makes them more understandable and easier to go thru so I’m very excited about this. + +### Three Courses + +I didn’t really explain too much about how this is going to work. I mentioned a few times that there will be 3 courses but didn’t go into details…​ + +The goal is to create something that’s more manageable for you and for us. An important part of taking a course is completing it and this is often difficult. However, if it’s three courses you can set a goal to finish one each month and it would be far more attainable. + +Segmenting the material allows more structure and ideally more people reaching that coveted 100% complete stage! + +The courses will be: + + * **Java for Mobile Devices** – This is the “learn Codename One” course. It covers the basics that all Codename One developers should know + + * **Deep Dive into Mobile** – This course goes into all of the complex features of Codename One and builds a non-trivial application. In fact it builds the [restaurant app](/blog/restaurant-app-builder.html) + + * **Build Real World Full Stack Mobile Apps in Java** – is the pinnacle of this trio. It continues where the deep dive ended and builds the full restaurant app builder application. It covers the server side and goes into deep details on everything. I’ll add at least 8 additional apps to this course over the next two years making it even more compelling than it is now + +### What about the Apps? + +We will produce at least one new module for the courses every month for the next two years. + +Guaranteed! + +That means at least 24 additional modules beyond what we have on launch. + +Once every 3 months (once a quarter) we’ll build a complete application as a module. Based on the current vote results it seems that the first app will be an Uber clone. In the module I’ll implement the app and teach you how to build such an app. This means we’ll implement 8 additional apps in total over the next two years (in additional to the 2 already in the course) and I’ll teach you how to build each one of those apps. + +I think this update commitment is crucial to keep the material fresh and up to date. + +Speaking about this, thanks again for taking the time and [voting](https://goo.gl/forms/XpiKZp8JPj5fhWTQ2)! + +This is the current set of results: + +![App preference results](/blog/how-does-it-work/app-pref-survey.png) + +Figure 1. App preference results + +This isn’t final yet and I’ll redo a survey after launch for the 3rd app onwards so the question is whose number 2 after Uber clone? + +That’s still open…​ + +### What will be Covered? + +These are pretty huge courses that literally cover **everything** you need to bring apps to production from idea to UI design all the way to deploying your cloud server to a VPS. + +I don’t like cutting corners so I try to cover as much as possible. Since the courses will be updated over the years and add additional application types I’m very confident that this scope will further expand with samples and subjects as we move forward. + +### What if I’m a Beginner? Can I take all 3 courses? + +This depends on stamina, they are designed in sequence and the material gets harder on a curve. The first course should be easy, the second moderate and the third is harder…​ +There probably won’t be blood sweat and tears (hopefully) but the final course isn’t easy. + +The final course is designed to teach practical real world development techniques and that might be difficult for some. It’s an advanced course that will hopefully prepare you for real world workloads, problems & shortcuts. + +### Would I get Assistance in Completing the Course? + +As usual you will get all the regular help in the [forum](/discussion-forum.html), [stackoverflow](https://stackoverflow.com/tags/codenameone) etc. Since this is an official course from Codename One we can answer the questions there. + +Furthermore, the course itself also includes discussion per module which you can also use. It has the advantage of being a part of the course and that way you can help future students using the course by asking the relevant questions. + +### Will this Material be Exclusively in the Course? + +Yes. This is material that’s built specifically for these courses. Some of the materials were featured in the bootcamp or based on materials that appeared there but most of the material is either completely new or reworked. It won’t be available anywhere else for the next two years. + +### Is there any time commitment like we had in the bootcamp? + +No. This is a standard course and you can take it at your leasure. Access to the course isn’t time limited. +Teachable (who we use for our new course materials) used the term perpetual which I personally find “problematic” as I’m pretty sure access will not survive the Sun going supernova. + +Having said that, we plan to keep the course online as long as possible and ideally as long as it’s useful. We also guarantee new materials will be added to the courses over the next 2 years at least! + +### Is there a Certification Process? + +Not at this time. We’d like to add Codename One certification but this is a pretty difficult process to go thru (on our side). + +However, the best way to market your skills is by showcasing an attractive application. Showing and deploying such an application is a core goal of this course. + +### Coming Soon + +At first I thought we should launch the new courses with the 3.7 release next week. However, one might overshadow the other so we’ll publish the courses Monday and release Codename One 3.7 on Tuesday. Keep an eye on this…​ + +Two weeks after registration closed for the bootcamp we still got a lot of emails from people claiming they didn’t know the bootcamp was available or sold out. I felt I sent too many emails but people still missed it and were very disappointed. I hope we don’t get something like this with the coming launch so please keep an eye on the blog next week. + +Thanks again for all the great feedback, comments & votes. They are all highly appreciated especially when they are mixed with constructive criticism. Please keep it coming and let me know what you think. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — June 22, 2017 at 12:22 pm ([permalink](https://www.codenameone.com/blog/how-does-it-work.html#comment-21426)) + +> Thank you! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-does-it-work.html) + + +### **Jérémy MARQUER** — June 22, 2017 at 1:32 pm ([permalink](https://www.codenameone.com/blog/how-does-it-work.html#comment-23386)) + +> Jérémy MARQUER says: +> +> Happy to see that CN1 is on the good way and you are really listening to customers 🙂 +> +> I would like to inform you one major difficulty I had, when I start working with codenameone : project architecture. +> As you know, few years ago, principle of CN1 was StateMachine class, in which we could find ALL the code. It was pretty difficult to organize my code. I’ve tried to apply a pseudo MVC architecture to my project but it was a bit difficult with this “StateMachine” class. So I’ve decided to handcoded all my form (and erase all from GuiBuilder). In addition, you have changed the manner form was build with the new gui builder. We have now one class for one form. What I didn’t like much was that everything was in a form class : UI construction as well as event management. I can now tell you my architecture : +> – “controller” for pure calcul +> – “dao” for database access +> – “model” +> – “service” for interfacing dao +> – “view” with all my form, dialog and components +> – “viewController” which contains all the event management and controllers invocation +> +> About view and viewController : each classes in viewController have a maching view (Form, Dialog or Container). Every main classes of my view are manage by a class : “ComponentManager”. Same as for viewController : “ComponentControllerManager”. All of my views and controller’s view are singleton and could be recreate by manager. +> +> I tell you that because I noticed all demos aren’t so much organize which must, in my opinion, not be the case for bigger application. I didn’t say my method is the best, but I wanted to let you know. +> +> Maybe it could be a good idea to have an architecture course 🙂 +> Just a word about 3.7 : I’ve installed successfully on Eclipse Luna (which was impossible with 3.6). New gui builder doesn’t seems to work. I think it should be better on Eclipse Neon. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-does-it-work.html) + + +### **Dalvik** — June 22, 2017 at 2:26 pm ([permalink](https://www.codenameone.com/blog/how-does-it-work.html#comment-23476)) + +> Dalvik says: +> +> Can’t wait 😉 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-does-it-work.html) + + +### **Shai Almog** — June 22, 2017 at 2:52 pm ([permalink](https://www.codenameone.com/blog/how-does-it-work.html#comment-23507)) + +> Shai Almog says: +> +> Thanks! +> I actually spend a lot of time talking about architecture in the courses. I cover both client and server architecture & how to tie them all together. I go into details such as cases where architectural decisions I take in the server impact security or the UX of the final app. It’s not an architecture course as it’s very pragmatic though. +> +> The old GUI builder which we are no longer using used an architecture that made a lot of sense on J2ME devices where every class file we added impacted size/performance and we tried to save on creating new class files. The new GUI builder is far more conventional in that sense and with the 3.7 release coming Tuesday it’s getting a MAJOR facelift… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-does-it-work.html) + + +### **Manuel Tijerino** — June 22, 2017 at 9:32 pm ([permalink](https://www.codenameone.com/blog/how-does-it-work.html#comment-24217)) + +> Manuel Tijerino says: +> +> Please let me know when these courses come out, would be very useful, thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-does-it-work.html) + + +### **Shai Almog** — June 23, 2017 at 4:36 am ([permalink](https://www.codenameone.com/blog/how-does-it-work.html#comment-23323)) + +> Shai Almog says: +> +> I’ll send out an email so if you got my last couple of emails over the past few days this shouldn’t be a problem. +> +> It’s launching on Monday and on Tuesday we have 3.7 which is shaping up as a pretty amazing release… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-does-it-work.html) + + +### **james agada** — June 23, 2017 at 12:16 pm ([permalink](https://www.codenameone.com/blog/how-does-it-work.html#comment-22074)) + +> james agada says: +> +> waiting of the course. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-does-it-work.html) + + +### **Lukman Javalove Idealist Jaji** — June 23, 2017 at 11:16 pm ([permalink](https://www.codenameone.com/blog/how-does-it-work.html#comment-23412)) + +> Lukman Javalove Idealist Jaji says: +> +> Do you already know how much the course will cost? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-does-it-work.html) + + +### **Shai Almog** — June 24, 2017 at 5:12 am ([permalink](https://www.codenameone.com/blog/how-does-it-work.html#comment-23452)) + +> Shai Almog says: +> +> We’ll offer multiple options +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-does-it-work.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/how-i-chose-my-replacement-for-parse-com-part-2.md b/docs/website/content/blog/how-i-chose-my-replacement-for-parse-com-part-2.md new file mode 100644 index 0000000000..0d3865b9c3 --- /dev/null +++ b/docs/website/content/blog/how-i-chose-my-replacement-for-parse-com-part-2.md @@ -0,0 +1,181 @@ +--- +title: How I Chose my Replacement for Parse.com Part 2 +slug: how-i-chose-my-replacement-for-parse-com-part-2 +url: /blog/how-i-chose-my-replacement-for-parse-com-part-2/ +original_url: https://www.codenameone.com/blog/how-i-chose-my-replacement-for-parse-com-part-2.html +aliases: +- /blog/how-i-chose-my-replacement-for-parse-com-part-2.html +date: '2016-08-08' +author: Shai Almog +--- + +![Header Image](/blog/how-i-chose-my-replacement-for-parse-com-part-2/parse.com-post-header.jpg) + +You probably recently received the “Next Steps from the Parse Team” newsletter in your inbox in which you were urged to take immediate action as it pertains to migrating your Parse.com-hosted apps. Or at least, you’re aware of the ultimate January 28, 2017 deadline for migrating your apps. While you should take such reminders seriously, there’s no need to panic. In this article, I share my experience with different Parse Server hosting backends and my choice after applying the principles outlined in [Part 1](/blog/how-i-chose-my-replacement-for-parse-com.html) of this series. Read on! + +### Applying the principles + +As I mentioned in Part 1, at the time that the imminent shutdown of Parse.com was announced, I had a few apps on Parse.com: + + * Parse4cn1 which is actually a Codename One wrapper for the Parse REST API but was hosted on Parse.com in order to test the library. + + * Two prototypes both in development at the time Parse.com’s shutdown was announced. (These apps still need to be migrated and this post is an extended version of my input to my clients as I help them choose a new backend.) + +Let’s begin by applying the principles outlined in Part 1 to parse4cn1. (Feel free to jump to the next section if you’re itching to see the backends I investigated.) + + 1. Self-hosting vs. Parse Server hosting providers: For parse4cn1, I considered both self-hosting and Parse Server hosting providers. In fact, I’m actually using both options, given the fact that I need parse4cn1 to work properly with various Parse Server-based backends. More on the backends shortly. + + 2. Vendor lock-in: This was not an issue for parse4cn1. The goal of parse4cn1 is to provide a wrapper for Parse Server so vendor-specific features are not quite interesting in this context. And like I suggested in Part 1, the chance of vendor lock-in is directly proportional to the amount of vendor-specific features used (none in the case of parse4cn1 so no risk of vendor lock-in). + + 3. Freemium: Contrary to the general principle about being wary of overly generous freemium packages, I want to be able to maintain parse4cn1 for free. So in this case, freemium is a plus. However, that does not detract from the fact that you should beware of overly generous freemium models. + + 4. Parse Server is not a clone of Parse.com: The main implication of this for me was the need to have a stable test environment in which I could easily switch Parse Server versions and debug issues. OpenShift turned out to be a great solution for this as I explain later in the article. + + 5. Making parse4cn1 future proof and migration-friendly: For parse4cn1, this means that it needs to keep working with Parse.com (until January 28, 2017) and also work with as many Parse Server providers as possible. To achieve that, I migrated parse4n1 to and tested it on multiple Parse Server backends. Let’s now look at those backends. + +### Test driving various Parse Server backends + +#### OpenShift: Great for development but not yet production ready + +OpenShift is a PaaS on which you can run various applications. Building up the work of Ionut-Cristian Florescu (alias [“icflorescu”](https://github.com/icflorescu)), OpenShift expert (at least in my eyes) [Anatoly Tokalov](https://plus.google.com/101404724521695639107/about) (alias [“antt”](https://github.com/antt)) has created a one-click solution to setup a Parse Server on OpenShift. I collaborated with him to integrate Parse Dashboard into this solution. So, with a few easy steps, it is now possible to set your own Parse Server backend for free on OpenShift! You can read more about the steps on [Anatoly’s blog](http://www.anttdev.com/2016/02/how-to-install-your-own-parse-server-on-openshift/). + +Having your own Parse Server sandbox can be tremendously useful as you migrate. You can easily switch between different Parse Server versions e.g. to track down bugs (that’s how I found [this one](https://github.com/ParsePlatform/parse-server/issues/2103), for instance). You can try different configurations out and get an initial feeling as to whether Parse Server is mature enough for your app. Regardless of what Parse Server backend you choose, I highly recommend an OpenShift sandbox. + +Be careful though! As pointed out by Anatoly in the same [blog post](http://www.anttdev.com/2016/02/how-to-install-your-own-parse-server-on-openshift/) (see Update 1 and Update 2 as well as the comments on the post), **Parse Server on OpenShift is not yet production ready!** +Moreover, at the time of writing, it is not (yet) possible to use the migration tool provided by Parse.com to migrate your apps to OpenShift because the mongodb instance in OpenShift is not accessible externally. + +So to summarize: OpenShift is a good place to test things out and arguably faster to set up than on your local machine. And it is free. However, at the time of writing, it is not production ready. I’m currently using OpenShift for parse4cn1 maintenance. The [automated regression tests](https://travis-ci.org/sidiabale/parse4cn1) currently run against OpenShift and against Parse.com (for compatibility checks). I also manually tested parse4cn1 against two Parse Server hosting providers – back4app and sashido.io. Let’s have a look at them. + +#### back{4}app: An attractive solution + +[Back4app](https://www.back4app.com/) is one of the Parse Server hosting providers looking to fill the void created by Parse.com. They use the Open Source Parse Server and Parse Dashboard as core and provide free and paid services around it with a pricing model quite comparable to Parse.com. The last part of the previous sentence caught your attention, didn’t’ it? Perhaps you’re thinking, “Parse.com shut down probably in part due to financial reasons and back4app has a similar freemium-based model yet you say it could be interesting?” Hang on, let me explain. And by the way, I have no affiliation with back4app, sashido.io, OpenShift or any other backend provider; all I’m going to say next is completely my personal opinion. + +Yes, I think back4app is promising and here’s why: + + * They seem to understand very well that former Parse.com users are disgruntled and sceptical. They are open about this; see, for example, these back4app blog posts: ([i](http://blog.back4app.com/2016/05/03/parse-alternative/))([ii](http://blog.back4app.com/2016/07/07/baas-market/)). Moreover, their comparisons of different Parse alternatives (e.g. this one on [Parse Server](http://blog.back4app.com/2016/06/15/firebase-parse/) vs. Firebase) seem quite balanced which again is a sign to me that they understand the situation and are not just reacting to the opportunity offered by Parse.com’s shutdown without thinking things through. + + * They also are clear about your data: It’s yours and you can have it anytime according to back4app this FAQ answer. I’ve not tried exporting my data yet though so I’m only working with what is said. Check it out for yourself! + + * They stick quite closely to the Parse Server offering – you can see the Parse Server and Dashboard version your app is running on and they clearly state what services they’ve added that are not yet supported (e.g. background jobs). This helps reduce the chance of vendor-lock in. + + * They’ve made some improvements that could make life easier, for example, the option to upload cloud code via a Web interface. I really hated that CLI tool from Parse.com and the fact that I had to push all my changes to test them. With back4app, you still have to “push” your changes to test them but you can simply upload your .js file via a web interface. I find that a good step in the right direction. + + * Their customer service is friendly and supportive. At least that was my experience when I contacted them about this [bug](https://github.com/ParsePlatform/parse-server/issues/2103). I encountered it for the first time when testing parse4cn1 against back4app and I thought it was in their system. But they confirmed that they use the Parse Server code as-is so I looked further and found that the bug was actually in Parse Server. During the process of debugging, they were supportive and very responsive via live chat and email. + +The big question mark for me is back4app’s freemium offering. Not as generous as Parse.com’s but in my opinion still somewhat too generous for comfort. As at the time of writing back4app offers 10 Requests/s, 50 K Requests/mo, 5 GB File Storage, 1 GB Database Storage, 1 cloud code job (read: background job) for free. Note though that the pricing page gets updated (read: tightened) from time to time so it could be that things have changed by the time you read this. + +I still find the current freemium package too generous as a lot of apps can run comfortably without ever needing to upgrade to a paid subscription which is not a good foundation for continuity in my opinion. Of course, I don’t know their business model. It could be that they want to use a decent freemium offer to attract as many users as possible and then “raise the heat”. That won’t be such a bad idea. Recall that there’s no free lunch. It’s better you pay a little and have a service that stays alive than to get a lot for free and face another shutdown! + +#### Sashido.io: An interesting alternative + +In many ways, [Sashido.io](http://www.sashido.io/) (previously Parseground) is similar to back4app. However, there are a few significant differences: + + * Unlike back4app, Sashido touts the “freemium is bad” slogan. At the time of writing, their home page has the following (emphasis added): “No limit of monthly requests & req. per second, storage, database and file transfer. And the best part? It starts from $4.95/mo. Better than free.” +They even wrote [an article](https://medium.com/@sashidoio/dangers-and-benefits-of-the-freemium-model-what-did-we-learn-out-of-parses-shutdown-79becb215c84#.ck7dsersi) on why freemium is bad. While that article makes sense, their approach of simply a 14-day trial and no freemium package is somewhat extreme in my opinion. By the way, I got a 2-month free trial due to early subscription. Often mobile projects start off as modest ideas and I don’t know many people who would be willing to incur monthly costs for a backend when they are not sure if their MVP would see the light of day. In that sense, I’m as opposed to overly generous freemiums as I am to no freemiums. + + * Sashido uses a custom dashboard instead of Parse Dashboard. While their dashboard is as intuitive as the Parse Dashboard and is designed very much to look like the Parse.com dashboard, this could be an issue in the future. As the open source Parse Dashboard gets enriched with new functionality, there is no guarantee that sashido will keep up or make the same choices with their dashboard. Something to definitely consider carefully if you choose sashido. + + * Sashido does use the open source Parse Server though. At least that’s [what they told us](https://twitter.com/sashidoio/status/758586000717279232). However, it’s useful to note that their dashboard does not (yet) mention what version of Parse Server they are running. I find that useful information and I hope they’ll add it soon. (Note that the Parse Server and dashboard version are present in the open source Parse Dashboard and by extension in back4app as well.) + + * As at the time of writing, there is no terms of service link on sashido.io’s homepage or any mention of what happens with your data if you opt-out. They don’t seem to be very open about the whole vendor lock-in fear. It might be a small omission on the website or it could be that the information is hidden somewhere and I didn’t look properly. But in any case, I expect this information to be prominent and easily accessible because it is at the center of the discussion and should not be relegated to the background. + +Sashido does offer some features that might be interesting to you such as [deploying cloud code](https://blog.sashido.io/how-to-set-up-cloud-code-on-sashido/) via a private Github repo and a [file migration tool](https://blog.sashido.io/parse-migration-in-a-click/) from Parse.com to AWS (available to all Parse.com users but only useful if you want to store your files in Amazon S3). + +### Moving forward + +There are a bunch of other services like back4app and sashido each having their pros and cons. I’ve not investigated all of them and honestly have no immediate plans to. parse4cn1 has successfully been tested against back4app and sashido as stated in this article. so they are both potential options. If I have to choose though, based on the current state of affairs, I’d go for back4app because I find their service overall more appealing and the risk of lock-in less than with sashido. I think this holds in general for small and medium-sized apps. In any case, I’ll always maintain an OpenShift sandbox in parallel for development and debugging. + +One thing that both back4app and sashido are missing at the moment is the option to switch versions of Parse Server per app. The way it works now is that they decide at some point to upgrade to a particular Parse Server version and developers have no say in that. It would be super cool if one could choose the Parse Server version to run a specific app on and/or decide when to upgrade…​ And this is not an unrealistic dream! In a sense, the fall of Parse.com has opened the door to many new opportunities…​ + +### The future is brighter with Parse Server + +Beyond the shock and fury at the shutdown of Parse.com, there is a silver lining and a bright future. The decision by Facebook to open source Parse Server and Dashboard might prove to be a game changer in the MBaaS space. It offers developers a decent backend out of the box and endless possibilities to customize and improve it. MBaaS is still somewhat of a gamble and skeptics suggest that an in-house solution is always the best. With Parse Server, you can get the best of both worlds! For instance, you can start off out with a Parse Server hosting provider and if your app becomes a hit and your needs necessitate an in-house solution, you can then smoothly migrate your Parse Server. If you app is one of the thousands that doesn’t see the light of day, you won’t have lost much in backend investment (especially if you chose a provider with a freemium model). + +Of course, the main thrust of this two part series has been to help you make a wise choice now and avoid another shutdown. But the truth is, even if you face another shutdown, the impact will be way less than Parse.com’s shutdown because you’ll have good alternatives and if you followed my advice, your app users won’t even notice that you switched backends again. That is the power of the open source solution offered by Parse Server! + +### Final word + +In this article, I’ve presented three Parse Server solutions, outlining their main pros and cons and clearly indicating my preferences. Note that I’ve deliberately not addressed “how to migrate” as there is a lot of useful information on that subject in the Parse.com [migration guide](https://www.parse.com/migration) as well as on the website of each Parse Server hosting provider. As such, there is no point in repeating what you can readily find yourself + +Of course, your app might differ in scope and purpose from the example that I’ve used in this article. Nevertheless, I’m pretty sure that if you follow my line of thought and apply the guidelines I’ve outlined in this series thoughtfully, you’d find a good replacement for your apps as well. I’ve shared the facts as well as my opinions with you; it’s now up to you to double-check and make your own choice; in that sense you have the final word! + +If you know of other attractive solutions, have success stories/useful tips to share and/or disagree with my reasoning/opinion, do not hesitate to leave a comment! Should the information in these articles and complementary ones on the Internet not suffice, feel free to [get in touch](/cdn-cgi/l/email-protection#21484f474e61524c4052490c4842550f424e4c) with us at SMash ICT for personalised consultation or contact me personally at chidi [dot] okwudire [at] smash-ict [dot] com. I wish you the very best with choosing your own replacement for Parse.com and would be glad to assist you in any way possible! + +### References and interesting reads + +[1] Anatoly Tokalov (February 19, 2016). How to install your own Parse Server on OpenShift. Retrieved from +[2] Marian Ignev (April 28, 2016). Dangers and benefits of the freemium model — What did we learn out of Parse’s shutdown? Retrieved from +[3] Alysson Melo (July 7, 2016). Challenges and Opportunities in the BaaS Market. Retrieved from +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Marian Ignev** — September 25, 2016 at 4:31 am ([permalink](https://www.codenameone.com/blog/how-i-chose-my-replacement-for-parse-com-part-2.html#comment-22973)) + +> Marian Ignev says: +> +> Hi Chidiebere Okwudire, very interesting article, great job, But … let me introduce myself. I’m part of the SashiDo team, so I want to share some thoughts with you … if you allow me of course 🙂 +> +> The things about SashiDo are wrong! Sorry … but they just are not true. +> +> – SashiDo Dashboard is 100% based on the OpenSource Parse Dashboard (I mean fork) and it’s improved by SashiDo. You had only to say that you write an article about SashiDo and we would love to tell you all the details 😉 +> +> – About my article for the Freemium business model please correct me but the title I think is “Dangers and benefits of the freemium model ” … not Freemium is bad thing … is that correct? 🙂 The only place that I used the word BAD was the there I told that …. Shutting down of good services like Parse is a bad thing … and yes I’m sure that a lot of Parse customers will agree with me now 🙂 +> +> In other hand as an entrepreneur I think that danger is a good thing … it’s exciting and keeps you focused, all the time. +> +> The last thing I want to share with you is that the free trial is not freemium 🙂 Just an example … You can do a Test Drive before you buy a car, right? To understand what’s the difference between the freemium and the free trial I have a challenge for you: Please thing about implementing a freemium model for the auto motor industry 🙂 +> +> I just wanted to share the true — no hard feelings here. +> +> All best, +> Marian +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-i-chose-my-replacement-for-parse-com-part-2.html) + + +### **Chidiebere Okwudire** — September 29, 2016 at 11:00 am ([permalink](https://www.codenameone.com/blog/how-i-chose-my-replacement-for-parse-com-part-2.html#comment-22965)) + +> Chidiebere Okwudire says: +> +> Hi Marian, +> +> Thanks for your response. Great to see that you’ve taken the time to point out some things that you consider incorrect in my analysis! Let me respond: +> +> You suggest that what I say about Sashido is wrong and you go ahead to point out a few issues like the dashboard and freemium model. I’ll respond to those shortly but just to be clear, I mentioned other things about Sashido and I assume that since you didn’t say anything about those, they are correct. If not, please feel free to refute anything else that you feel is wrong in my article. My goal with these articles is to help developers make a right choice so I’m 100% in favor of accurate and correct information and input from folks like you is very much appreciated. +> +> Now to your remarks: +> +> 1\. In the article, I state that “Sashido uses a custom dashboard instead of Parse Dashboard”. This is based on an inspection of the Sashido dashboard when I still had a free trial account a few months ago. I don’t know how it *looks* now but at the time I wrote the article, the differences from the default Parse Dashboard were impossible to miss (I might even have a screenshot somewhere) – Parse Server and dashboard versions were not reported, the menu items were somewhat different, etc. +> +> You’ve clarified that your version is forked from the open source Parse Dashboard and that’s nice to know. However, my point was (and remains) that with such a highly customized dashboard (albeit based on Parse Dashboard), there’s still a risk of lock in. Would you disagree? For example, a user wanting to switch from Sashido to say back4app would have to (at least) deal with a different looking dashboard with different options, etc. And I have a strong feeling there’s more that’s different than just the look-and-feel. Maybe you’d like to comment on that so readers can have a more balanced picture. Like I said, my free trial of Sashido has ended and I don’t plan to make another trial account to point out all the differences. The interested reader can do this for themselves 🙂 +> +> 2\. About the Freemium model, you’re right that my wording in the article might incorrectly give the impression that the author is completely against Freemium whereas the article does *try* to compare both sides. I emphasize “try” here because in my opinion, the article is baised in favor of the dangers of freemium than the benefits. Again, let the interested reader be the judge. Let’s not get too distracted by the article though because I think the more important point in this context is: Is Sashido a freemium service or not? What’s your take on that? Note that [http://www.sashido.io/#Pricing]() still include the line that I quoted in my article: “It starts from $4.95/mo. Better than free.” +> +> I look forward to your response and once again thanks for taking your time to engage in this conversation. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-i-chose-my-replacement-for-parse-com-part-2.html) + + +### **Marian Ignev** — September 30, 2016 at 2:38 am ([permalink](https://www.codenameone.com/blog/how-i-chose-my-replacement-for-parse-com-part-2.html#comment-22997)) + +> Marian Ignev says: +> +> Hi Chidiebere, +> +> Thank you for your detailed answer. I appreciate it and I’m totally agree with you … let the interested reader be the judge I think that’s fair 🙂 +> +> And yes … SashiDo is not a free service, but everybody can try it 14 days for free 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-i-chose-my-replacement-for-parse-com-part-2.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/how-i-chose-my-replacement-for-parse-com.md b/docs/website/content/blog/how-i-chose-my-replacement-for-parse-com.md new file mode 100644 index 0000000000..b9e9c906f2 --- /dev/null +++ b/docs/website/content/blog/how-i-chose-my-replacement-for-parse-com.md @@ -0,0 +1,168 @@ +--- +title: How I Chose my Replacement for Parse.com +slug: how-i-chose-my-replacement-for-parse-com +url: /blog/how-i-chose-my-replacement-for-parse-com/ +original_url: https://www.codenameone.com/blog/how-i-chose-my-replacement-for-parse-com.html +aliases: +- /blog/how-i-chose-my-replacement-for-parse-com.html +date: '2016-07-19' +author: Shai Almog +--- + +![Header Image](/blog/how-i-chose-my-replacement-for-parse-com/parse.com-post-header.jpg) + +When I first read the announcement that Parse.com would shut down on January 28th 2017, I went from +disbelief (it’s probably an early April fool’s joke) to rage (how could they do that?!) to sadness (oh no! it was a +great service) and finally to utter confusion (where do I go from here and what do I do with my apps – +[parse4cn1](https://github.com/sidiabale/parse4cn1), two [MVPs](https://www.smash-ict.com/#projects) for clients +and an upcoming rewrite of +[Medex](https://play.google.com/store/apps/details?id=com.mosync.app_Medex) for which I was planning to use +Parse.com as backend?). A few months down the line, a lot has happened such as the release of the open source +Parse Server (yay!) and subsequently the Parse Dashboard. However, I still had to decide what do with my apps +and I guess you have to as well. + +By now, the imminent shutdown of Parse.com must have hit home for you as well: You wish it was merely a bad dream but unfortunately it’s a stark reality. You’ve got just a few months left to migrate your existing apps and obviously do not want to face another shutdown. Nearly every major MBaaS vendor is brandishing a banner that directly or indirect says “Parse.com let you down but you’re safe with us”. However, whom can you trust? Or maybe you should just host your own Parse Server? How about migrating away from anything Parse-like and settling for a completely different MBaaS. + +In this post, I share some important points to consider while deciding on your replacement for Parse.com. In Part 2, I’ll share how I applied these guidelines while migrating my own apps. This article is highly recommended for anyone who still has their apps on Parse.com or is contemplating using a Parse.com-like solution as backend for their (new) apps. + +### There Are Basically 3 Options + +Don’t be intimidated by the long lists of Parse.com alternatives that you may have seen (for example, this one). Broadly speaking, all Parse.com alternatives fit into one of the following three categories: + + 1. Self-hosting + + 2. Parse Server hosting provider + + 3. Other MBaaS (unrelated to Parse) + +Let’s briefly consider these categories and give some examples. + +#### Self-hosting + +Self-hosting comes in two flavors: + + * Running Parse Server on a PaaS infrastructure such as Heroku, AWS, Microsoft Azure or Google App Engine. The Parse Server wiki provides links to installation guides for these services and more. + + * Running Parse Server on your own infrastructure. This could be attractive if you already have your own platform and/or if you require on-premises hosting. + +#### Parse Server hosting provider + +These are BaaS providers who have leveraged the open-source Parse Server to create Parse.com-like services. Some of the providers in this category are back4app, ParseGround (now called SashiDo) and Oursky Parse Hosting to mention just a few. + +__ | A more comprehensive list can be found [here](https://github.com/relatedcode/ParseAlternatives#parse-server-hosting-providers). +Note that I cannot ascertain how up-to-date it is…​ +---|--- + +Undoubtedly, this category of Parse.com alternatives will be attractive to most of the users who chose Parse.com in the first place because of its ease of use, rich feature set and/or intuitive dashboard. Although Parse Server is not a clone of Parse.com, it is quite similar in terms of features and even has some new features like live queries which were not present in Parse.com. As such Parse Server is definitely an alternative worth considering! + +As already mentioned above, there are several providers in this category. If you take this route, you’ll need to choose one of them. While there is no silver bullet or crystal ball to help you make that choice, I’ll highlight important aspect that you must take into consideration while choosing your Parse.com replacement. But first, let’s consider the third category of Parse.com alternatives. + +#### Other MBaaS solutions + +Shortly after Parse.com announced the imminent shutdown, various lists of alternatives appeared on the Internet. +Consider, for example, [this list](https://github.com/relatedcode/ParseAlternatives) of 100 or more alternatives to Parse.com. (Note that the list also includes alternatives from the other two categories.) + +While Parse.com offered a rich feature set, it was not ideal for all use cases. For example, Parse.com was (and by extension Parse Server is) not suited for real-time messaging. If you’re one of those who found Parse’s offering insufficient for your use case, then this is a good time to consider other MBaaS options that could better meet your needs including the possibility of an in-house custom solution. While you’re at it though, watch out for signs of vendor lock-in and do not be fooled by false assurances that a particular MBaaS is reliable simply because it is backed up by a big company. If Facebook pulled the plugs on Parse, any of those big-company-backed solutions can face the same fate! That’s the reality. + +The rest of this article will focus on the first two categories (i.e. self-hosting and Parse Server hosting providers). + +### 5 Things to Bear in Mind + +Now that you have a better idea of what the options are, here are some things you must bear in mind while making your choice for your Parse.com replacement. + +#### Self-hosting is more than merely clicking a “Deploy on X” button + +Most self-hosting Parse migration guides display a “Deploy on ” button. While this might help you through the initial migration, it is only the tip of the iceberg! Self-hosting requires non-trivial investment of time and resources; it requires a certain degree of technical competence and could be quite expensive in the long run. + +On the other hand, self-hosting offers you maximum flexibility from choice of database to Parse server version (remember that Parse Server is still in active development so there are regular updates, bug fixes, etc.). Furthermore, you can add new functionality that is not (yet) available in Parse Server. + +If you’re considering self-hosting, be sure to give yourself convincing answers to questions like: + + * Do I have the technical skills to maintain my own Parse Server? In addition to supporting your apps, you’re suddenly going to also be responsible for several quality aspects like scalability, security, redundancy and reliability. Can you cope with that especially if your app has a significant user base? + + * Is self-hosting financially viable for me? It might look cheap at the beginning but as your app’s audience grows, you’ll probably need to scale. While it is out of the scope of this article to go into detailed cost calculations, I’d like to point you to this article on how much self-hosting using AWS could cost as well as this discussion thread by other Parse Server enthusiasts on cost considerations. The main message here is: Do not underestimate the costs! + + * Do I have sufficient time to set up my Parse Server and migrate all my apps? You have till January 28, 2017 to get done with migration and that’s not so much time. In fact, according to the migration guide provided by Parse.com, you should already have finished setting up your Parse Server by July 28, 2016. While that’s not a firm deadline, if you’re reading this article now and still haven’t chosen your self-hosting PaaS, you’re kind of running late…​ + +If you cannot provide satisfactory answers to questions like the ones above, self-hosting is likely not for you. Instead, consider a Parse Server hosting provider that will handle the hosting for you, allowing you to focus on making great apps. That was the power of Parse.com – “focus on your apps and we’ll take care of the rest”. And it remains a strong value proposition. + +#### Beware of vendor lock-in + +This is particularly relevant if you choose for the Parse Server hosting category. Parse Server and Parse Dashboard are open source so you might be wondering why vendor lock-in is a potential issue. Let me explain. + +Parse Server was open sourced with a BSD license model. While I’m not a software licensing expert, my understanding of this license is that it allows users to modify the source without releasing such modifications. Sooner or later, Parse Server hosting providers will begin to add their own features and I can bet you that not all of them will be willing to contribute back to the open source Parse Server. Every feature from a Parse Server hosting provider that is not present in the open source Parse Server is a potential lock-in! Think of what will happen if your new provider shuts down. Obviously, Parse Server will remain open source so there will be alternative providers. However, you’ll be stuck with those custom features that are no longer supported. + +Other possible symptoms of potential vendor lock-in are unclear terms and conditions with regard to your data and migration in the event of a shutdown. Let’s be frank: Parse.com has provided a decent migration plan and, as far as I can tell, they’re doing their best to support us through the process. Your next provider should be able to commit upfront to something similar or better in case the undesirable happens. + +Moreover, you’d be much better off with a Parse Server hosting provider that is actively involved in adding features and fixing bugs in the open source Parse Server repository over one that just promises to occasionally give back with no evidence whatsoever. + +#### Beware of elaborate Freemium offers + +As the adage goes “Once bitten, twice shy!” With the unprecedented shutdown of Parse.com, you definitely do +not want to migrate your apps only to face another shutdown. So be careful with very attractive freemium offers. +One of my college professors often reminded us that “there’s no such thing as a free lunch” and I think he was right. + +Although the [announcement](http://blog.parse.com/announcements/moving-on/) of Parse.com’s shutdown didn’t +provide details of why Facebook pulled the plugs, the main reason is apparently $$$ as explained in +[this New York Times article](http://bits.blogs.nytimes.com/2016/01/28/facebook-to-shut-down-parse-its-platform-for-mobile-developers/?_r=1) +which, remarkably, was termed by Parse.com’s CEO, as +[“pretty accurate”](https://www.quora.com/Why-is-Parse-shutting-down/answer/Ilya-Sukhar?srid=uX6B5). +You might also find +[this article](https://medium.com/@sashidoio/dangers-and-benefits-of-the-freemium-model-what-did-we-learn-out-of-parses-shutdown-79becb215c84#.ggsb3gf6l) +on the dangers and benefits of the freemium model interesting. + +#### Parse Server is not a clone of Parse.com + +With the release of the open source Parse Server, one would expect that the Parse.com code was cleaned up +and open sourced. However, that is definitely not the case. While Parse Server has strong similarities to Parse.com, +it is only a look-alike and not a clone as clearly indicated in +[this discussion](https://github.com/ParsePlatform/parse-server/issues/765) involving Parse.com engineers. + +So bear in mind that there are difference some of which are listed on the Parse Server +[wiki](https://github.com/ParsePlatform/parse-server/wiki/Compatibility-with-Hosted-Parse). If your app relies +heavily on any of those features (e.g. background jobs or push notification support for Windows Phone), then Parse Server as-is does not (yet) meet your needs. The good news is that, now that it’s open source, you can (and should) contribute to making Parse Server better. You don’t have to wait until someone else builds it; you can make Parse Server richer by contributing new features! Alternatively, you could look for other ways to realize the missing functionality. Going back to the background jobs example, you could find other means to schedule background jobs or use a Parse Server provider like back4app which already implements that feature. Similarly, you could consider a separate service for multi-platform push notifications which can later be integrated with Parse Server via the +[PushAdapter](https://github.com/parse-server-modules/parse-server-push-adapter) mechanism. + +Another implication of the fact that Parse Server is not a clone of Parse.com is that there could be bugs and other issues that make it unfit for production especially for more complex apps, at least for the time being. While it is difficult to assess how production-ready Parse Server currently is, this +somewhat [outdated discussion](https://github.com/ParsePlatform/parse-server/issues/1106) might provide some insights. + +#### Make your app as future-proof as possible + +With the migration from Parse.com to Parse Server, you have to release a new version of your apps with at least the Parse endpoint changed from api.parse.com to whatever endpoint you’ll be using. While you’re at it, make sure to enrich your app with the intelligence of being able to dynamically switch to a new backend should the need ever arise in the future. In that way, you’ll have one thing less to worry about if the undesirable happens with your next provider. This is just one way you can make your apps future-proof. + +### How I chose my replacement for Parse.com + +In Part 2, I will explain how I applied the above guidelines in choosing a replacement for Parse.com. Watch out for the follow up post! + +### Conclusion + +In this article, I’ve given you some food for thought as you decide where to migrate your Parse.com-hosted apps to. +I’ve deliberately not recommended any particular self-hosting service or Parse Server hosting provider as there is +no one-size-fits-all solution. You’ll need to make that choice based on your app needs and your answers to the +(difficult?) questions posed in the article. In a sequel blog post, I will explain how I decided on my replacement for +Parse.com, highlighting strong and weak points of the Parse Server providers that I tested. If you still can’t make +any headway, feel free to get in touch or leave a comment. Also do not hesitate to share your thoughts on the subject! + +### References and interesting reads + + 1. Radek Zaleski (February 2016). Parse Is Done. What Now? 5 Tips How to Proceed with Migration. Retrieved from + + 2. Ron Palmeri (January 30, 2016). Why Facebook’s Parse shutdown is good news for all of us. Retrieved from + + 3. Marian Ignev (April 28, 2016). Dangers and benefits of the freemium model — What did we learn out of Parse’s shutdown? Retrieved from + + 4. Alysson Melo (May 3, 2016). Parse alternative: Self-hosting or Parse hosting provider? Retrieved from + + 5. Alysson Melo (June 15, 2016). Firebase vs. Parse Server. Retrieved from + + 6. Alysson Melo (June 21, 2016). How much cost Parse self-hosting? Retrieved from + + 7. Mike Isaac and Quentin Hardy (January 28, 2016). Facebook to Shut Down Parse, Its Platform for Mobile Developers. Retrieved from + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/how-to-build-a-clicking-tapping-game-tutorial.md b/docs/website/content/blog/how-to-build-a-clicking-tapping-game-tutorial.md new file mode 100644 index 0000000000..f0b502a999 --- /dev/null +++ b/docs/website/content/blog/how-to-build-a-clicking-tapping-game-tutorial.md @@ -0,0 +1,38 @@ +--- +title: How to Build a Clicking (Tapping) Game Tutorial +slug: how-to-build-a-clicking-tapping-game-tutorial +url: /blog/how-to-build-a-clicking-tapping-game-tutorial/ +original_url: https://www.codenameone.com/blog/how-to-build-a-clicking-tapping-game-tutorial.html +aliases: +- /blog/how-to-build-a-clicking-tapping-game-tutorial.html +date: '2016-07-12' +author: Shai Almog +--- + +![Header Image](/blog/how-to-build-a-clicking-tapping-game-tutorial/hqdefault.jpg) + +Over the weekend [LokeHansen](https://www.youtube.com/channel/UCULoPvQDYiLy0yAnHXy50Eg) posted a +new series of youtube videos covering the process of creating a game in Codename One. I really enjoyed watching +them as his teaching style is far more accessible than mine (I tend to be overly technical without noticing). + +I’m guessing the videos below might be a bit too simple for some of our typical readers but if you have friends or +kids who like games and didn’t connect to coding this might be a great tool to get them started, I’ve embedded +the first 3 videos in the series below. Check them out and +[subscribe to his channel](https://www.youtube.com/channel/UCULoPvQDYiLy0yAnHXy50Eg) for more. + +If you are doing such tutorials/guides that are relevant to Codename One just drop us a line and we’d be happy +to help you spread the word. + +### Introduction + +### Part II + +### Part III + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/how-to-build-ios-apps-with-java.md b/docs/website/content/blog/how-to-build-ios-apps-with-java.md new file mode 100644 index 0000000000..70be5d4f0f --- /dev/null +++ b/docs/website/content/blog/how-to-build-ios-apps-with-java.md @@ -0,0 +1,417 @@ +--- +title: How to Build iOS Apps with Java +slug: how-to-build-ios-apps-with-java +url: /blog/how-to-build-ios-apps-with-java/ +original_url: https://www.codenameone.com/blog/how-to-build-ios-apps-with-java.html +aliases: +- /blog/how-to-build-ios-apps-with-java.html +date: '2022-06-24' +description: Learn how to build and publish iOS apps with Java or Kotlin without a + Mac or Xcode in this comprehensive guide. +--- + +![How to Build iOS Apps with Java](/blog/how-to-build-ios-apps-with-java/Build-iOS-apps-with-Java-1024x536.png) + +Learn how to build and publish iOS apps with Java or Kotlin without a Mac or Xcode in this comprehensive guide. + +In this guide, we will get to know everything about iOS app development with Java. + +We will discuss the development process, technology involved, prerequisites and general FAQs for building apps for iPhone/iPad using Java. + +****Here are the major topics we’ve covered in this Java iOS app development guide.**** + +Java is one of the most popular programming languages around the world for everything from mobile development to enterprise and server-side applications. + +Being a general-purpose, object-oriented and cross-platform programming language, Java enables developers ****Write Once, Run Anywhere (WORA)****, meaning that a Java program could be developed on any device and can be expected to run on any hardware that has a ****JVM (Java Virtual Machine)****. + +Before we delve any further on how to code in Java for building iOS apps, we need to understand two most common approaches for app development… + +### Native App Development + +Developing a ****platform specific**** app using its ****native**** programming language is called native app development. + +For example, using Java or Kotlin for Android and Swift or Obj-C for iOS. + +### Cross-Platform App Development + +Developing apps using a ****single codebase**** that runs on ****multiple platforms**** refers to cross-platform app development. + +Some common cross-platform frameworks include Flutter, React Native and Codename One. + +****Related 📝**** [Top 10 Best Cross-Platform App Development Frameworks in 2023](https://www.codenameone.com/blog/top-10-best-cross-platform-app-development-frameworks-in-2023.html) + +> On Android, Java or Kotlin are the native languages whereas Apple's iOS platform relies on Swift and Obj-C as its native languages. + +## iOS App Development + +### How are iOS apps made? + +If you want to get into writing iOS apps for the iPhone, iPads etc, you have two options: + +### Code native iOS apps with Swift or Objective-C + +If you want to develop ****native apps**** for iOS, the official iOS SDK combined with Xcode allows you to write apps with Swift or Obj-C. + +### Use a cross-platform framework + +For those who don’t know or want to learn Swift, a suitable ****[cross-platform app development framework](https://www.codenameone.com/blog/top-10-best-cross-platform-app-development-frameworks-in-2022.html)**** can compile your code to native iOS executable. + +## Java vs Swift + +### What language to choose for iOS development? + +Java is the native language for Android while Swift is the native language for Apple devices (iOS, macOS, watchOS, tvOS). + +Both Java and Swift are static-type, object oriented and compiled programming languages. + +Swift is one of the newer programming languages while Java has been around for years. + +### Difference between Java and Swift: + +| Factors | Java | Swift | +| --- | --- | --- | +| Platform | Java is not platform dependent | Swift is dependent on iOS and MacOS | +| Syntax | Java is verbose and has complex syntax and code readability | Swift has easy syntax and code readability | +| Performance | Modern Java is quite fast. A well optimized Java app can be as fast as a native app | Swift is fast as it was built with performance in mind for Apple ecosystem | +| Security | Java is more secure compared to Swift with its byte-code verifier, JVM and security API's | Swift was designed to be memory safe. Swift can call Objective-C code which makes it prone to overflows | +| Popularity | Java is a mature and popular programming language. [Tiobe](https://www.tiobe.com/tiobe-index/) and [Redmonk](https://redmonk.com/sogrady/2022/03/28/language-rankings-1-22/) ranks Java at number 3 by popularity | Swift is reasonably popular for mobile development. [Tiobe](https://www.tiobe.com/tiobe-index/) and [Redmonk](https://redmonk.com/sogrady/2022/03/28/language-rankings-1-22/) ranks Swift at number 10 and 11 respectively | +| + +Both Java and Swift are quite different in terms of methods, syntax, code usability etc. + +Swift is obviously a preferred choice to develop apps specifically for the Apple ecosystem while Java is a preferred choice for Android development or cross-platform reusability. + +> The opportunity cost involved in learning Swift outweighs the benefits since its a platform dependant language. + +## Java on Apple Hardware + +### Why doesn't Apple support Java? + +By now you might be thinking ‘if Java code can run on any platform, why can’t Java run on iOS?’ + +Java can run on any platform that has a compatible Java Virtual Machine (JVM). Since Apple doesn’t support JVM for iOS, Java can’t run on iPhones and iPads. + +Apple makes sure that only Swift and Objective-C has 100% vendor support on iOS by forbidding alternative runtimes from being deployed on it. + +> Java developers have long been out in the cold with Apple when it comes to porting their apps on Apple devices. + +## Develop iOS apps with Java + +### iOS app development using Java is easier than you think. + +Everything we have discussed so far is not to say that you cannot develop iOS apps in Java. + +The only way to develop iOS apps in Java is to have a compiler that will compile your Java code down to native iOS binary. + +With ****Codename One****, Java developers can build apps that run on iOS devices such as the iPhone and iPad. Not only that, your app will work beyond iOS devices i.e Android, Windows and JavaScript. + +> Want to utilize your existing Java/Kotlin skills to develops iOS apps? You can do that with Codename One! + +If you’re not using Codename One yet, then sign up now: + +[Sign Up - It's Free!](https://www.codenameone.com/dashboard) + +## How Does It Work? + +### Underlying technology that enables Codename One to develop iOS apps with Java. + +Native iOS development requires a Mac with Xcode. To make matters worse, Apple makes changes to their tools on a regular basis. + +Codename One has a built-in simulator when running and debugging an app. For native iOS builds, Codename One build cloud uses Macs running Xcode (the native Apple tool) to build the app. + +This removes the need to install/update complex toolchains and simplify the process of building a native iOS app. + +[![Codename One - iOS Architecture](/blog/how-to-build-ios-apps-with-java/Group-1563.svg)](https://www.codenameone.com/introduction.html) + +[Codename One - iOS Architecture](https://www.codenameone.com/introduction.html) + +The process works seamlessly and makes Codename One apps native as they are literally compiled by the native platform. + +Java bytecode is dynamically translated to a native iOS Xcode project and seamlessly compiled to a native binary. This binary can be installed on iOS devices or uploaded to App Store. + +> • With Codename One, you don't need to have a Mac to develop iOS apps. +> +> • Codename One also provides an option to ****build offline****. +> +> • To understand how Codename One works, check our [developer guide](https://www.codenameone.com/developer-guide.html). + +## Prerequisites + +### What you need to get started. + +To run and build the project, you should be running a modern version of Mac OS, Windows, or Linux with JDK 11 installed. + +You don’t need to install anything other than the Codename One plugin. You can work with Mac, Windows or Linux and everything should “just work”. + +Let’s dig in. + +## Getting Started + +### Tutorial to walk you through the steps of building a Hello World app. + +1 + +#### Codename One initializer + +2 + +#### Open in IDE + +3 + +#### Develop & Debug App + +4 + +#### Create iOS Build + +### Step 1: Generate a new project with Codename One initializr + +The easiest and quickest way to create a new project is to use the [Codename One initializr](https://start.codenameone.com/). + +This online tool will allow you to choose from a growing selection of project templates in Java or Kotlin, and download a starter project that you can open in your preferred IDE or build directly on the command-line using Maven. + +![Codename One Initializr](/blog/how-to-build-ios-apps-with-java/1_4GPJ7_DpFLf9XGEcaBoaQQ.jpeg) + +Codename One initializr + +Important: +The package name you select for your app can’t be changed once the app is submitted to a store! + +• Go to [Codename One initializr](https://start.codenameone.com/), select the ****Java Bare-bones Project**** from the ****Template**** select box. + +• Enter a ****Package**** and ****Main Class**** for your app. The ****Package**** will be used both for your App ID, when you submit your app to the App Store, and for your Maven project’s `groupID`. The ****Main Class**** is the name of the `main` Java class for your app. + +• Press ****Download**** and save the project as a .zip file. + +• After the download completes, extract the zip file. + +Resources: +• [Getting Started with the Bare-bones Java App Template](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html). + +• [Online Tool to Generate iOS Starter Project](https://dev.to/shannah/online-tool-to-generate-ios-android-starter-project-k7h) + +• [Codename One Maven Developer Guide](https://shannah.github.io/codenameone-maven-manual/). + +### Step 2: Open the project in your preferred IDE + +You can run the project directly from the [command-line](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html#running-on-cli) or you can open it in your preferred IDE (e.g. [IntelliJ](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html#run-in-intellij) or [NetBeans](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html#run-in-netbeans)). + +For this tutorial, I’m going to use IntelliJ. + +As this is a Maven project, IntelliJ can open this project and work with it natively without requiring any special plugins. + +• Open the extracted project in IntelliJ (or your preferred IDE). + +• Press the green ![intellij run icon](/blog/how-to-build-ios-apps-with-java/intellij-run-icon.png) icon to run the app in the simulator. + +![](/blog/how-to-build-ios-apps-with-java/idea-toolbar.png) + +• Wait while Maven downloads the build dependencies. It will open the Codename One simulator with the simple ****Hello World**** app. + +### Step 3: Develop & Debug your app + +If you run this project in the Codename One Simulator without making any modifications to the app, it will look something like this: + +![](/blog/how-to-build-ios-apps-with-java/simulator-first-run.png) + +The simulator makes it easy to develop and debug your app without having to build and deploy to a real device. + +It includes a number of useful features aimed at streamlining the development process. + +Generally, you would work exclusively in the simulator until you have a near finished product that you want to share with your beta-testers. + +Resources: +• For more information about the ****Codename One simulator****, see this [page](https://www.codenameone.com/codename-one-simulator.html). + +• More information about the ****project structure, project files, editing Java code**** and ****CSS stylesheet**** can be found in this detailed [guide](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html). + +### Step 4: Build the project for iOS + +Finally, we can build a native app for iOS by running the Xcode iOS project target. + +When building for iOS, you can either ****build locally**** or via ****build server****. + +Tip: +We recommend using the ****build server**** as it doesn’t require installing any special development tools on the computer beyond the standard JDK. + +#### Build Server + +With Codename One build server, iOS apps can be built on Windows, Linux, or Mac with no special requirements beyond Maven and the JDK. All you need is a free Codename One account. + +For iOS builds, there are two build targets that use the build server: + +****• iOS Debug Build**** (for testing and debugging) + +****• iOS Release Build**** (to submit to the iOS App store) + +Note: +Before you can submit an iOS build to the build server, you need to go through a few of Apple’s requirements. See [iOS Prerequisites](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html#ios-prerequisites) for more information about these steps. + +• Click on the configuration menu in the upper right toolbar, and select ****Build Server**** > ****iOS Debug Build/iOS Release Build**** as shown below: + +![](/blog/how-to-build-ios-apps-with-java/intellij-build-ios-debug.png) + +Building for iOS via Build Server + +• Press the ![intellij run icon](/blog/how-to-build-ios-apps-with-java/intellij-run-icon.png) button to build the project. + +• After you submit the build, you can track and install them via ****Build Server****, ****Control Center**** or the ****Android Build app****. + +Resources: +• [Build Server](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html#build-app). + +• [Control Center](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html#settings). + +• [Android Build App](https://play.google.com/store/apps/details?id=com.codename1.build.app). + +#### Local iOS builds + +The Local iOS build target generates an Xcode iOS project that you can open and build directly in Xcode. + +Note: +This target necessarily requires a ****Mac with Xcode**** installed. See [Building for iOS](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html#ios)for more information. + +• Click on the ****Configuration**** menu in the upper right toolbar, and select ****Local Builds**** > ****Xcode iOS Project**** as shown below: + +![](https://www.codenameone.com/wp-content/uploads/2021/04/intellij-build-ios-project.png) + +Building locally for iOS + +• Press the ![intellij run icon](/blog/how-to-build-ios-apps-with-java/intellij-run-icon.png) button to build the project. + +• If all goes well, the project will be found in the `ios/target` directory. + +• You can proceed to open the Xcode project (.xcworkspace file) in Xcode, and build the project. + +Tip: +To build a native app, Codename One supports a variety of different target platforms: + + +ㅤAndroid + +ㅤ iOS + +ㅤ Windows + +ㅤ Mac + +ㅤJavaScript + +ㅤJavaSE + +## TLDR (Too Long Didn't Read) + +### All of the above is shown in this tutorial by Steve Hannah + +In this quick video, [Steve Hannah](https://sjhannah.com/blog/2021/04/07/video-building-a-codename-one-project-for-ios/) uses the bare-bones Java project generated by Codename One initializr, which he’s running in IntelliJ, to build for iOS. + +He also gives a brief tour of the project structure and build targets. + +## Resources + +There are several online sources for iOS app development tutorials using Java or Kotlin with Codename One. + +Here are some useful links: + +• [Codename One Docs](https://www.codenameone.com/developing-in-codename-one.html): The first steps, guides, tutorials and resources you need. + +• [Compare Codename One](https://www.codenameone.com/compare.html): Codename One’s comparison with other cross-platform frameworks. + +• [Codename One Maven Developer Guide](https://shannah.github.io/codenameone-maven-manual/) + +• [Getting Started with the Bare-bones Java App Template](https://shannah.github.io/cn1-maven-archetypes/cn1app-archetype-tutorial/getting-started.html) + +• [Building a Codename One project for iOS (Video)](https://sjhannah.com/blog/2021/04/07/video-building-a-codename-one-project-for-ios/) + +• [Build Cross-Platform Native Mobile Apps Using Java/Kotlin for iOS, Android, Desktop and Web](https://dzone.com/articles/create-native-mobile-apps-using-java-kotlin-and-ma) + +## The Community + +Codename One is backed by a vibrant community of more than 100k developers in over 200 countries. + +Codename One 1.0 was released in 2012 by ex-Sun engineers. It was the first solution to build native iOS apps in Java and it’s still the most mature, performant and stable cross-platform mobile toolkit for Java/Kotlin developers. + +Codename One Community: + + +ㅤ[GitHub](https://github.com/codenameone/CodenameOne) + + +ㅤ +[StackOverflow](https://stackoverflow.com/questions/tagged/codenameone) + +ㅤ +[Reddit](https://www.reddit.com/r/cn1/) + +##### Quick Start with Codename One initializr​ + +###### Build your first iOS app with Java/Kotlin now.​ + +[Get Started](https://start.codenameone.com/) + +## Frequently Asked Questions (FAQs) + +Can I run Java on iOS? + +Java code can't run on iPhone and iPad since there is no Java Virtual Machine (JVM) for iOS. However, Codename One can compile Java code to native iOS binary. + +Can I develop iOS apps without Swift? + +Yes, you can develop iOS apps without Swift using a compiler that can compile your code down to native iOS binary. + +Can I develop iOS apps with Java? + +Yes, if you are a Java developer, you don’t need to learn Swift or Objective-C to develop iOS apps. You can use Codename One to develop iOS apps using Java or Kotlin. + +Is Java good for iOS development? + +Java is a good choice for iOS app development if you: + +• Don’t know or want to learn Swift or Objective-C + +• Want to build a cross-platform app + +• Want easy deployment & maintenance + +• Want to save costs & resources + +Can I develop iOS apps without Xcode? + +Yes, you can build iOS apps without Xcode using Codename One, an open-source cross-platform framework for building native apps with Java/Kotlin. + +Do I need a Mac to develop iOS apps? + +No, with Codename One, you can develop and distribute iOS apps without a Mac, macOS or Xcode. + +Can I build iOS apps on Windows? + +Yes, you can build iOS apps on Windows using Codename One without using a Mac, macOS or Xcode. + +Is it legal to develop iOS apps on Windows? + +Yes, it's legal to develop iOS apps on non-Apple hardware or software as it does not violate the Apple Developer Agreement. + +How to build iOS apps with Java? + +You can build native iOS apps with Java using Codename One. Just sign up for a free Codename One account, go to Codename One initializr, and generate a starter project that you can open, run, debug, and build in your preferred IDE. + +How to build iOS apps with Kotlin? + +You can build native iOS apps with Kotlin using Codename One. Just sign up for a free Codename One account, go to Codename One initializr, and generate a starter project that you can open, run, debug, and build in your preferred IDE. + +## Final Thoughts + +Building iOS apps with Swift is the obvious route if you want to develop specifically for iOS only. + +But if you are a Java developer and don’t know Swift, Codename One is your best bet to develop iOS apps using Java or Kotlin. + +Getting started with Codename One is easy. Just sign up for a free Codename One account, go to Codename One initializr, and generate a starter project that you can open, run, debug, and build in your preferred IDE. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/how-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.md b/docs/website/content/blog/how-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.md new file mode 100644 index 0000000000..d9ca0fd036 --- /dev/null +++ b/docs/website/content/blog/how-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.md @@ -0,0 +1,215 @@ +--- +title: How to detect Jailbroken or Rooted device and hide sensitive data in background? +slug: how-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background +url: /blog/how-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background/ +original_url: https://www.codenameone.com/blog/how-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.html +aliases: +- /blog/how-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.html +date: '2021-05-21' +author: Steve Hannah +description: The following recipes relate to security of Codename One apps. This includes + detecting Jailbroken or Rooted device and hiding sensitive data when entering background. +--- + +The following recipes relate to security of Codename One apps. This includes detecting Jailbroken or Rooted device and hiding sensitive data when entering background. + +The following recipes include tips on making your Codename One apps more secure. + +### Detecting Jailbroken/Rooted Device + +## Problem + +You want to detect whether the device your app is running on is Jailbroken or Rooted. + +## Solution + +While there is no way to know whether the device is rooted with 100% certainty, you can use the [CN1JailbreakDetect](https://github.com/shannah/CN1JailbreakDetect) cn1lib to to make a good guess. + +This cn1lib acts as a thin wrapper around the [RootBeer](https://github.com/scottyab/rootbeer) Android library, and [DTTJailbreakDetection](https://github.com/thii/DTTJailbreakDetection) iOS library, which employ heuristics to determine whether the device has likely been jailbroken. + +## Example + +```java + + package com.codename1.samples; + +import com.codename1.ext.jailbreak.JailbreakDetect; +import static com.codename1.ui.CN.*; +import com.codename1.ui.Display; +import com.codename1.ui.Form; +import com.codename1.ui.Dialog; +import com.codename1.ui.Label; +import com.codename1.ui.plaf.UIManager; +import com.codename1.ui.util.Resources; +import com.codename1.io.Log; +import com.codename1.ui.Toolbar; +import java.io.IOException; +import com.codename1.ui.layouts.BoxLayout; +import com.codename1.io.NetworkEvent; +import com.codename1.ui.Button; +import com.codename1.ui.Command; + +public class JailbreakDetectionSample { + + private Form current; + private Resources theme; + + public void init(Object context) { + // use two network threads instead of one + updateNetworkThreadCount(2); + + theme = UIManager.initFirstTheme("/theme"); + + // Enable Toolbar on all Forms by default + Toolbar.setGlobalToolbar(true); + + // Pro only feature + Log.bindCrashProtection(true); + + addNetworkErrorListener(err -> { + // prevent the event from propagating + err.consume(); + if(err.getError() != null) { + Log.e(err.getError()); + } + Log.sendLogAsync(); + Dialog.show("Connection Error", "There was a networking error in the connection to " + err.getConnectionRequest().getUrl(), "OK", null); + }); + } + + public void start() { + if(current != null){ + current.show(); + return; + } + Form hi = new Form("Jailbreak Detection", BoxLayout.y()); + Button detect = new Button("Detect Jailbreak"); + detect.addActionListener(evt->{ + if (JailbreakDetect.isJailbreakDetectionSupported()) { + if (JailbreakDetect.isJailbroken()) { + Dialog.show("Jailbroken","This device is jailbroken", new Command("OK") ); + } else { + Dialog.show("Not Jailbroken", "Probably not jailbroken. But can't be 100% sure.", new Command("OK")); + } + } else { + Dialog.show("No Idea", "No support for jailbreak detection on this device.", new Command("OK")); + } + }); + hi.add(detect); + hi.show(); + } + + public void stop() { + current = getCurrentForm(); + if(current instanceof Dialog) { + ((Dialog)current).dispose(); + current = getCurrentForm(); + } + } + + public void destroy() { + } + +} + + +``` + +## Tip: + +> This sample is part of the [Codename One samples](https://github.com/codenameone/CodenameOne/tree/master/Samples) project, and can be run directly from the Codename One SampleRunner. + +## Discussion + +The [CN1JailbreakDetect](https://github.com/shannah/CN1JailbreakDetect) provides two useful static methods for jailbreak detection: + +1. isJailbreakDetectionSupported() – This checks if the jailbreak detection is even supported on this platform. + + +2. isJailBroken() – This checks if the device is jailbroken. If detection is not supported, then this will always return false. + +Currently jailbreak detection is only supported on Android and iOS. + +## Important: + +> There is NO way to know with 100% certainty whether or not a device has been jailbroken. + +## Further Reading + +1. [CN1JailbreakDetect github project](https://github.com/shannah/CN1JailbreakDetect) +2. [RootBeer project](https://github.com/scottyab/rootbeer) (Used on Android) +3. [DTTJailbreakDetection project](https://github.com/thii/DTTJailbreakDetection) (Used on iOS) + +### Hiding Sensitive Data When Entering Background + +## Problem + +iOS will take a screenshot of your app when it enters the background that it uses for various previews of the app state. You want to hide sensitive data in your app’s UI to prevent this information from leaking out via these screenshots. + +## Solution + +You can use the ios.blockScreenshotsOnEnterBackground=true build hint to prevent iOS from taking screenshots app goes into the background. This will cause the canvas on which the Codename One UI is drawn to be hidden in the didEnterBackground hook and unhidden in the willEnterForeground hook. + +## Warning: + +> This will cause your app to appear as a blank white rectangle when the user is browsing through opened apps. + +![](https://www.codenameone.com/wp-content/uploads/2021/05/Image-270420-124718.733.png) + +> Figure 1. Notice the app in the middle is blank white because it has been set to block iOS screenshots. + +## Discussion + +You might have been tempted to try to modify the UI inside the stop() lifecycle method of your app, since it is called itself by the didEnterBackground hook. + + +This strategy will work in some platforms, but not on iOS because the screenshot call is made immediately upon the didEnterBackground method returning – and the stop() method runs on the EDT (a different thread), so this is not possible. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved here for historical context. New discussion happens in the Discussion section below._ + + +### **Javier Anton** — May 24, 2021 at 11:06 am ([permalink](https://www.codenameone.com/blog/how-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.html#comment-24454)) + +> Javier Anton says: +> +> Very useful. There are lots of rooted users that hack in-app purchases and get things for free. I wonder how effective RootBeer is, I know there are tools available to hide the root at the moment +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.html) + + +### **Javier Anton** — May 24, 2021 at 12:30 pm ([permalink](https://www.codenameone.com/blog/how-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.html#comment-24455)) + +> Javier Anton says: +> +> Just looked at the RootBeer code and it looks great. It even checks natively in cpp, which I read was the safest way to bypass root masks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.html) + + +### **Javier Anton** — May 24, 2021 at 12:45 pm ([permalink](https://www.codenameone.com/blog/how-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.html#comment-24456)) + +> Javier Anton says: +> +> Is there any reason RootBeer version 0.0.8 is used and not 0.0.9? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.html) + + +### **Javier Anton** — May 24, 2021 at 2:49 pm ([permalink](https://www.codenameone.com/blog/how-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.html#comment-24457)) + +> Javier Anton says: +> +> Nevermind, I just added the native bits myself. Wish I could delete/edit my posts on here, maybe that could be enabled at some point +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-detect-jailbroken-or-rooted-device-and-hide-sensitive-data-in-background.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/how-to-port-jvm-languages-to-codename-one.md b/docs/website/content/blog/how-to-port-jvm-languages-to-codename-one.md new file mode 100644 index 0000000000..aa9efdf051 --- /dev/null +++ b/docs/website/content/blog/how-to-port-jvm-languages-to-codename-one.md @@ -0,0 +1,465 @@ +--- +title: 'Tutorial: How to Add Support for other JVM Languages' +slug: how-to-port-jvm-languages-to-codename-one +url: /blog/how-to-port-jvm-languages-to-codename-one/ +original_url: https://www.codenameone.com/blog/how-to-port-jvm-languages-to-codename-one.html +aliases: +- /blog/how-to-port-jvm-languages-to-codename-one.html +date: '2017-07-17' +author: Steve Hannah +--- + +![Header Image](/blog/how-to-port-jvm-languages-to-codename-one/kotlin_800x320.png) + +As you may have already read, we have just added support for Kotlin in Codename One. In this post, I elaborate on some of the behind the scene work that was involved in bringing Kotlin to Codename One. + +## What is a JVM Language? + +A JVM Language is any programming language that can be compiled to byte-codes that will run on the JVM (Java Virtual Machine). Java was the original JVM language, but many others have sprung up over the years. [Kotlin](https://kotlinlang.org/), [Scala](https://www.scala-lang.org/), [Groovy](http://groovy-lang.org/), and [JRuby](http://jruby.org/) come to mind as well-established and mature languages, but there are [many others](https://en.wikipedia.org/wiki/List_of_JVM_languages). + +## How Hard is it to Port a JVM Language to Codename One? + +The difficulty of porting a particular language to Codename One will vary depending on such factors as: + + 1. Does it require a runtime library? + + 1. How complex is the runtime library? (E.g. Does it require classes that aren’t currently offered in Codename One’s subset of the java standard libraries?) + + 2. Does it need reflection? + + 1. Codename One doesn’t support reflection because it would result in a very large application size. If a JVM language requires reflection just to get off the ground then adding it to Codename one would be tricky. + + 3. Does it perform any runtime byte-code manipulation? + + 1. Some dynamic languages may perform byte-code manipulation at runtime. This is problematic on iOS (and possibly other platforms) which prohibits such runtime behaviour. + +### Step 1: Assess the Language + +The more similar a language, and its build outputs are to Java, the easier it will be to port (probably). Most JVM languages have two parts: + + 1. A compiler, which compiles source files to JVM byte-code (usually as .class files). + + 2. A runtime library. + +Currently I’m only aware of one language (other than Java) that doesn’t require a runtime library, and that is [Mirah](http://www.mirah.org/). + +__ | Codename One also supports [Mirah](https://www.codenameone.com/blog/mirah-for-codename-one.html) +---|--- + +#### Assessing the Byte-Code + +The first thing I do is take a look at the byte-code that is produced by the compiler. I use `javap` to print out a nice version. + +Consider this sample Kotlin class: + + + package com.codename1.hellokotlin2 + + import com.codename1.ui.Button + import com.codename1.ui.Form + import com.codename1.ui.Label + import com.codename1.ui.layouts.BoxLayout + + /** + * Created by shannah on 2017-07-10. + */ + class KotlinForm : Form { + + constructor() : super("Hello Kotlin", BoxLayout.y()) { + val label = Label("Hello Kotlin") + val clickMe = Button("Click Me") + clickMe.addActionListener { + label.setText("You Clicked Me"); + revalidate(); + } + + add(label).add(clickMe); + + } + + + } + +Let’s take a look at the bytecode that Kotlin produced for this class: + + + $ javap -v com/codename1/hellokotlin2/KotlinForm.class + Classfile /Users/shannah/IdeaProjects/HelloKotlin2/out/production/HelloKotlin2/com/codename1/hellokotlin2/KotlinForm.class + Last modified 10-Jul-2017; size 1456 bytes + MD5 checksum 1cb00f6e63b918bb5a9f146ca8b0b78e + Compiled from "KotlinForm.kt" + public final class com.codename1.hellokotlin2.KotlinForm extends com.codename1.ui.Form + SourceFile: "KotlinForm.kt" + InnerClasses: + static final #31; //class com/codename1/hellokotlin2/KotlinForm$1 + RuntimeVisibleAnnotations: + 0: #56(#57=[I#58,I#58,I#59],#60=[I#58,I#61,I#58],#62=I#58,#63=[s#64],#65=[s#55,s#66,s#6,s#67]) + minor version: 0 + major version: 50 + flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER + Constant pool: + #1 = Utf8 com/codename1/hellokotlin2/KotlinForm + #2 = Class #1 // com/codename1/hellokotlin2/KotlinForm + #3 = Utf8 com/codename1/ui/Form + #4 = Class #3 // com/codename1/ui/Form + #5 = Utf8 + #6 = Utf8 ()V + #7 = Utf8 Hello Kotlin + #8 = String #7 // Hello Kotlin + #9 = Utf8 com/codename1/ui/layouts/BoxLayout + #10 = Class #9 // com/codename1/ui/layouts/BoxLayout + #11 = Utf8 y + #12 = Utf8 ()Lcom/codename1/ui/layouts/BoxLayout; + #13 = NameAndType #11:#12 // y:()Lcom/codename1/ui/layouts/BoxLayout; + #14 = Methodref #10.#13 // com/codename1/ui/layouts/BoxLayout.y:()Lcom/codename1/ui/layouts/BoxLayout; + #15 = Utf8 com/codename1/ui/layouts/Layout + #16 = Class #15 // com/codename1/ui/layouts/Layout + #17 = Utf8 (Ljava/lang/String;Lcom/codename1/ui/layouts/Layout;)V + #18 = NameAndType #5:#17 // "":(Ljava/lang/String;Lcom/codename1/ui/layouts/Layout;)V + #19 = Methodref #4.#18 // com/codename1/ui/Form."":(Ljava/lang/String;Lcom/codename1/ui/layouts/Layout;)V + #20 = Utf8 com/codename1/ui/Label + #21 = Class #20 // com/codename1/ui/Label + #22 = Utf8 (Ljava/lang/String;)V + #23 = NameAndType #5:#22 // "":(Ljava/lang/String;)V + #24 = Methodref #21.#23 // com/codename1/ui/Label."":(Ljava/lang/String;)V + #25 = Utf8 com/codename1/ui/Button + #26 = Class #25 // com/codename1/ui/Button + #27 = Utf8 Click Me + #28 = String #27 // Click Me + #29 = Methodref #26.#23 // com/codename1/ui/Button."":(Ljava/lang/String;)V + #30 = Utf8 com/codename1/hellokotlin2/KotlinForm$1 + #31 = Class #30 // com/codename1/hellokotlin2/KotlinForm$1 + #32 = Utf8 (Lcom/codename1/hellokotlin2/KotlinForm;Lcom/codename1/ui/Label;)V + #33 = NameAndType #5:#32 // "":(Lcom/codename1/hellokotlin2/KotlinForm;Lcom/codename1/ui/Label;)V + #34 = Methodref #31.#33 // com/codename1/hellokotlin2/KotlinForm$1."":(Lcom/codename1/hellokotlin2/KotlinForm;Lcom/codename1/ui/Label;)V + #35 = Utf8 com/codename1/ui/events/ActionListener + #36 = Class #35 // com/codename1/ui/events/ActionListener + #37 = Utf8 addActionListener + #38 = Utf8 (Lcom/codename1/ui/events/ActionListener;)V + #39 = NameAndType #37:#38 // addActionListener:(Lcom/codename1/ui/events/ActionListener;)V + #40 = Methodref #26.#39 // com/codename1/ui/Button.addActionListener:(Lcom/codename1/ui/events/ActionListener;)V + #41 = Utf8 com/codename1/ui/Component + #42 = Class #41 // com/codename1/ui/Component + #43 = Utf8 add + #44 = Utf8 (Lcom/codename1/ui/Component;)Lcom/codename1/ui/Container; + #45 = NameAndType #43:#44 // add:(Lcom/codename1/ui/Component;)Lcom/codename1/ui/Container; + #46 = Methodref #2.#45 // com/codename1/hellokotlin2/KotlinForm.add:(Lcom/codename1/ui/Component;)Lcom/codename1/ui/Container; + #47 = Utf8 com/codename1/ui/Container + #48 = Class #47 // com/codename1/ui/Container + #49 = Methodref #48.#45 // com/codename1/ui/Container.add:(Lcom/codename1/ui/Component;)Lcom/codename1/ui/Container; + #50 = Utf8 clickMe + #51 = Utf8 Lcom/codename1/ui/Button; + #52 = Utf8 label + #53 = Utf8 Lcom/codename1/ui/Label; + #54 = Utf8 this + #55 = Utf8 Lcom/codename1/hellokotlin2/KotlinForm; + #56 = Utf8 Lkotlin/Metadata; + #57 = Utf8 mv + #58 = Integer 1 + #59 = Integer 6 + #60 = Utf8 bv + #61 = Integer 0 + #62 = Utf8 k + #63 = Utf8 d1 + #64 = Utf8 + nn20¢¨ + #65 = Utf8 d2 + #66 = Utf8 Lcom/codename1/ui/Form; + #67 = Utf8 HelloKotlin2 + #68 = Utf8 KotlinForm.kt + #69 = Utf8 Code + #70 = Utf8 LocalVariableTable + #71 = Utf8 LineNumberTable + #72 = Utf8 SourceFile + #73 = Utf8 InnerClasses + #74 = Utf8 RuntimeVisibleAnnotations + { + public com.codename1.hellokotlin2.KotlinForm(); + descriptor: ()V + flags: ACC_PUBLIC + Code: + stack=5, locals=3, args_size=1 + 0: aload_0 + 1: ldc #8 // String Hello Kotlin + 3: invokestatic #14 // Method com/codename1/ui/layouts/BoxLayout.y:()Lcom/codename1/ui/layouts/BoxLayout; + 6: checkcast #16 // class com/codename1/ui/layouts/Layout + 9: invokespecial #19 // Method com/codename1/ui/Form."":(Ljava/lang/String;Lcom/codename1/ui/layouts/Layout;)V + 12: new #21 // class com/codename1/ui/Label + 15: dup + 16: ldc #8 // String Hello Kotlin + 18: invokespecial #24 // Method com/codename1/ui/Label."":(Ljava/lang/String;)V + 21: astore_1 + 22: new #26 // class com/codename1/ui/Button + 25: dup + 26: ldc #28 // String Click Me + 28: invokespecial #29 // Method com/codename1/ui/Button."":(Ljava/lang/String;)V + 31: astore_2 + 32: aload_2 + 33: new #31 // class com/codename1/hellokotlin2/KotlinForm$1 + 36: dup + 37: aload_0 + 38: aload_1 + 39: invokespecial #34 // Method com/codename1/hellokotlin2/KotlinForm$1."":(Lcom/codename1/hellokotlin2/KotlinForm;Lcom/codename1/ui/Label;)V + 42: checkcast #36 // class com/codename1/ui/events/ActionListener + 45: invokevirtual #40 // Method com/codename1/ui/Button.addActionListener:(Lcom/codename1/ui/events/ActionListener;)V + 48: aload_0 + 49: aload_1 + 50: checkcast #42 // class com/codename1/ui/Component + 53: invokevirtual #46 // Method add:(Lcom/codename1/ui/Component;)Lcom/codename1/ui/Container; + 56: aload_2 + 57: checkcast #42 // class com/codename1/ui/Component + 60: invokevirtual #49 // Method com/codename1/ui/Container.add:(Lcom/codename1/ui/Component;)Lcom/codename1/ui/Container; + 63: pop + 64: return + LocalVariableTable: + Start Length Slot Name Signature + 32 32 2 clickMe Lcom/codename1/ui/Button; + 22 42 1 label Lcom/codename1/ui/Label; + 0 65 0 this Lcom/codename1/hellokotlin2/KotlinForm; + LineNumberTable: + line 13: 0 + line 14: 12 + line 15: 22 + line 16: 32 + line 21: 48 + } + +That’s a big mess of stuff, but it’s pretty easy to pick through it when you know what you’re looking for. The layout of this output is pretty straight forward. The beginning shows that this is a class definition: + + + public final class com.codename1.hellokotlin2.KotlinForm extends com.codename1.ui.Form + +Even just comparing this line with the class definition from the source file we have learned something about the Kotlin compiler. It has made the class `final` by default. That observation shouldn’t affect our assessment here, but it is kind of interesting. + +After the class definition, it shows the internal classes: + + + InnerClasses: + static final #31; //class com/codename1/hellokotlin2/KotlinForm$1 + +**The Constant Pool** + +And the constants that are used in the class: + + + Constant pool: + #1 = Utf8 com/codename1/hellokotlin2/KotlinForm + #2 = Class #1 // com/codename1/hellokotlin2/KotlinForm + #3 = Utf8 com/codename1/ui/Form + #4 = Class #3 // com/codename1/ui/Form + #5 = Utf8 + #6 = Utf8 ()V + #7 = Utf8 Hello Kotlin + #8 = String #7 // Hello Kotlin + #9 = Utf8 com/codename1/ui/layouts/BoxLayout + ... etc... + +The constant pool will consist of class names, and strings mostly. You’ll want to peruse this list to see if the compiler has added any classes that aren’t in the source code. In the example above, it looks like Kotlin is pretty faithful to the original source’s dependencies. It didn’t inject any classes that aren’t in the original source. + +Even if the compiler does inject other dependencies into the bytecode, it might not be a problem. It is only a problem if those classes aren’t supported by Codename One. Keep your eyes peeled for anything in the `java.lang.reflect` package or unsolicited use of `java.net`, `java.nio`, or any other package that aren’t part of the Codename One standard library. If you’re not sure if a class or package is available in the Codename One standard library, check [the javadocs](https://www.codenameone.com/javadoc/). + +**The ByteCode Instructions** : + +After the constant pool, we see each of the methods of the class written out as a list of bytecode instructions. E.g. + + + public com.codename1.hellokotlin2.KotlinForm(); + descriptor: ()V + flags: ACC_PUBLIC + Code: + stack=5, locals=3, args_size=1 + 0: aload_0 + 1: ldc #8 // String Hello Kotlin + 3: invokestatic #14 // Method com/codename1/ui/layouts/BoxLayout.y:()Lcom/codename1/ui/layouts/BoxLayout; + 6: checkcast #16 // class com/codename1/ui/layouts/Layout + 9: invokespecial #19 // Method com/codename1/ui/Form."":(Ljava/lang/String;Lcom/codename1/ui/layouts/Layout;)V + 12: new #21 // class com/codename1/ui/Label + 15: dup + 16: ldc #8 // String Hello Kotlin + etc... + +In the above snippet, the first instruction is `aload_0` (which adds `this` to the stack). The 2nd instruction is `ldc`, (which loads constant #8 — the string “Hello Kotlin” to the stack). The 3rd instruction is `invokestatic` which calls the static method define by Constant #14 from the constant pool, with the two parameters that had just been added to the stack. + +__ | You don’t need to understand what all of these instructions do. You just need to look for instructions that may be problematic. +---|--- + +The only instruction that I **think** might be problematic is “invokedynamic”. All other instructions should work find in Codename One. (I don’t know for a fact that invokedynmic won’t work – I just suspect it might not work on some platforms). + +**Summary of Byte-code Assessment** + +So to summarize, the byte-code assessment phase, we’re basically just looking to make sure that the compiler doesn’t tend to add dependencies to parts of the JDK that Codename One doesn’t currently support. And we want to make sure that it doesn’t use invokedynamic. + +If you find that the compiler does use invokedynamic or add references to classes that Codename One doesn’t support, don’t give up just yet. You might be able to create your own “porting” runtime library that will provide these dependencies at runtime. + +#### Assessing the Runtime Library + +The process for assessing the runtime library is pretty similar to the process for the bytecodes. You’ll want to get your hands on the language’s runtime library, and use `javap` to inspect the .class files. You’re looking for the same things as you were looking for in the compiler’s output: “invokedynamic” and classes that aren’t supported in Codename One. + +### Step 2: Convert the Runtime Library into a CN1Lib + +Once you have assessed the language and are optimistic that it is a good candidate for porting, you can proceed to port the runtime library into Codename One. Usually that language’s runtime library will be distributed in .jar format. You need to convert this into a cn1lib so that it can be used in a Codename One project. If you can get your hands on the source code for the runtime library then the best approach is to paste the source files into a Codename One Library project, and try to build it. This has the advantage that it will validate the source during compile to ensure that it doesn’t depend on any classes that Codename One doesn’t support. + +If you can’t find the sources of the runtime library or they don’t seem to be easily “buildable”, then the next best thing is to just get the binary distribution’s jar file and convert it to a cn1lib. This is what I did for the [Kotlin runtime library](https://github.com/shannah/codenameone-kotlin). + +This procedure exploits the fact that a cn1lib file is just a zip file with a specific file structure inside it. The cross-platform Java .class files are all contained inside a file named “main.zip”, inside the zip file. This is the only **mandatory** file that must be inside a cn1lib. + +To make the library easier to use the cn1lib file can also contain a file named “stubs.zip” which includes stubs of the Java sources. When you build a cn1lib using a Codename One Library project, it will automatically generate stubs of the source so that the IDE will have access to nice things like Javadoc when using the library. The kotlin distribution includes a separate jar file with the runtime sources, named “kotlin-runtime-sources.jar”, so I used this as the “stubs”. It contains full sources, which isn’t necessary, but it also doesn’t hurt. + +So now that I had my two jar files: kotlin-runtime.jar and kotlin-runtime-sources.jar, I created a new empty directory, and copied them inside. I renamed the jars “main.zip” and “stubs.zip” respectively. Then I zipped up the directory and renamed the zip file “kotlin-runtime.cn1lib”. + +__ | Building cn1libs manually in this way is a **very** bad habit, as it bypasses the API verification step that normally occurs when building a library project. It is possible, even likely, that the jar files that you convert depend on classes that aren’t in the Codename One library, so your library will fail at runtime in unexpected ways. The only reason I could do this with kotlin’s runtime (with some confidence) is because I already analyzed the bytecodes to ensure that they didn’t include anything problematic. +---|--- + +### Step 3: Hello World + +For our “Hello World” test we will need to create a separate project in our JVM language and produce class files that we will **manually** copy into an appropriate location of our project. We’ll want to use the **normal** tools for the language and not worry about how it integrates with Codename One. For Kotlin, I just followed the getting started tutorial on the Kotlin site to create a new Kotlin project in IntelliJ. When I ported Mirah, I just used a text editor and the mirahc command-line compiler to create my Hello World class. The tools and process will depend on the language. + +Here is the “hello world” I created in Kotlin: + + + package com.mycompany.myapp + + class HelloKotlin { + + fun hello() { + System.out.println("Hello from Kotlin"); + } + } + +After building this, I have a directory that contains “com/mycompany/myapp/HelloKotlin.class”. + +It also produced a .jar file that contains this class. + +I have found that the easiest way to integrate external code into a Codename One project, is just to wrap it as a cn1lib file and place it into my Codename One project’s lib directory. That way I don’t have to mess with any of the build files. So, using roughly the same procedure as I used to create the kotlin-runtime.cn1lib, I wrap my hellokotlin.jar as a cn1lib to produce “hellokotlin.cn1lib” and copy it to the “lib” directory of a Codename One project. + +__ | Remember to select “Codename One” → “Refresh CN1Libs” after placing the cn1lib in your lib directory or it won’t get picked up. +---|--- + +Finally, I call my library from the start() method of my app: + + + HelloKotlin hello = new HelloKotlin(); + hello.hello(); + +If I run this in the Simulator, it should print “Hello from Kotlin” in the output console. If I get an error, then I dig in and try to figure out what went wrong using my standard debugging techniques. **EXPECT** an error on the first run. Hopefully it will just be a missing import or something simple. + +### Step 4: A More Complex Hello World + +In the case of Kotlin, the hello world example app would actually run without the runtime library because it was so simple. So it was necessary to add a more complex example to prove the need for the runtime library. It doesn’t matter what you do with your more complex example, as long as it doesn’t require classes that aren’t in Codename One. + +If you want to use the Codename One inside your project, you should add the CodenameOne.jar (found inside any Codename One project) to your classpath so that it will compile. + +### Step 5: Automation and Integration + +At this point we already have a manual process for incorporating files built with our alternate language into a Codename One project. The process looks like: + + 1. Use standard tools for your JVM language to write your code. + + 2. Use the JVM language’s standard build tools (e.g. command-line compiler, etc..) to compile your code so that you have .class files (and optionally a .jar file). + + 3. Wrap your .class files in a cn1lib. + + 4. Add the cn1lib to the lib directory of a Codename One project. + + 5. Use your library from the Codename One project. + +When I first developed Mirah support I just automated this process using an [ANT script](https://github.com/shannah/CN1MirahNBM/blob/master/src/ca/weblite/codename1/mirah/build.xml). I also automatically generated some bootstrap code so that I could develop the whole app in Mirah and I woudn’t have to write any Java. However, I soon found that this level of integration has limitations. + +For example, with this approach alone, I couldn’t have two-way dependencies between Java source and Mirah source. Yes, my Mirah code could use Java libraries (and it did depend on CodenameOne.jar), and my Java code could use my Mirah code. However, my Mirah **source** code could not depend on the Java **source** code in my project. This has to do with the order in which code is compiled. It’s a bit of a chicken and egg issue. If we are building a project that has Java source code and Mirah source code, we are using two different compilers: mirahc to compile the Mirah files, and javac to compile the Java files. If we are starting from a clean build, and we run mirahc first, then the .java files haven’t yet been compiled to .class files – and thus mirahc can’t **reference** them – and any mirah code that depends on those uncompiled Java classes will fail. If we compile the .java files first, then we have the opposite problem. + +I worked around this problem in Mirah by writing [my own pseudo-compiler](https://github.com/shannah/mirah-ant/blob/master/src/ca/weblite/asm/JavaExtendedStubCompiler.java) that produced stub class files for the java source that would be referenced by mirahc when compiling the Mirah files. In this way I was able to have two-way dependencies between Java and Mirah in the same project. + +Kotlin also supports two-way dependencies, probably using a similar mechanism. + +#### How Seamless Can You Make It? + +For both the Kotlin and Mirah support, I wanted integration to be seamless. I didn’t want users to have to create a separate project for their Kotlin/Mirah code. I wanted them to simply add a Kotlin/Mirah file into their project and have it **just work**. Achieving this level of integration in Kotlin was quite easy, since they provide an [ANT plugin](https://kotlinlang.org/docs/reference/using-ant.html) that essentially allowed me to just add one tag inside my `` tags: + + + + +And it would automatically handle Kotlin and Java files together: Seamlessly. There are a few places in a Codename One’s build.xml file where we call “javac” so we just needed to inject these tags in those places. This injection is performed automatically by the Codename One IntelliJ plugin. + +For Mirah, I developed my own [ANT plugins](https://github.com/shannah/mirah-ant) and [Netbeans module](https://github.com/shannah/mirah-nbm) that do something similar in Netbeans. + +## Which Language Will Be Next? + +Hacking on JVM byte-code can actually be a lot of fun. If you are interested in adding support for a language, we’d love to know about it. Until then, happy coding! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Gareth Murfin** — July 18, 2017 at 1:19 pm ([permalink](https://www.codenameone.com/blog/how-to-port-jvm-languages-to-codename-one.html#comment-23526)) + +> Gareth Murfin says: +> +> Incredible work. So will the gui builder spit out kotlin too ? Also I think adding swift for iOS native dev would be awesome!.. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-port-jvm-languages-to-codename-one.html) + + +### **Don't Bother** — July 18, 2017 at 5:07 pm ([permalink](https://www.codenameone.com/blog/how-to-port-jvm-languages-to-codename-one.html#comment-23307)) + +> Don't Bother says: +> +> Swift is already a native language for iOS. So I don’t really understand what you are asking for. And I have not heard about ability to complie swift to java bytecode. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-port-jvm-languages-to-codename-one.html) + + +### **shannah78** — July 18, 2017 at 6:35 pm ([permalink](https://www.codenameone.com/blog/how-to-port-jvm-languages-to-codename-one.html#comment-21522)) + +> shannah78 says: +> +> Not sure about the maturity of this, but here’s one. [https://github.com/brettwoo…](). If someone wants to try to add swift support to Codename One, it might make for an interesting exercise. +> +> This is not to be confused with using Swift to write native iOS code in a Codename one native interface. This is already possible (albiet a bit painful) by building a library separately using swift/xcode, and including the library in your ios/native lib – You only need to write a small amount of Objective-C to serve as the native interface itself. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-port-jvm-languages-to-codename-one.html) + + +### **Gareth Murfin** — July 19, 2017 at 2:19 am ([permalink](https://www.codenameone.com/blog/how-to-port-jvm-languages-to-codename-one.html#comment-23497)) + +> Gareth Murfin says: +> +> Oh thats interesting is there any links for that? I I want to write more native libs but I want to use swift. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-port-jvm-languages-to-codename-one.html) + + +### **Shai Almog** — July 19, 2017 at 5:08 am ([permalink](https://www.codenameone.com/blog/how-to-port-jvm-languages-to-codename-one.html#comment-23624)) + +> Shai Almog says: +> +> That’s a very different thing. The main blocker for this is integrating ARC with the GC. That should work in theory but doesn’t. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-port-jvm-languages-to-codename-one.html) + + +### **Adi J** — August 6, 2017 at 1:11 pm ([permalink](https://www.codenameone.com/blog/how-to-port-jvm-languages-to-codename-one.html#comment-21853)) + +> Adi J says: +> +> can I make app for tizen os along with android and ios by codename one. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-port-jvm-languages-to-codename-one.html) + + +### **Shai Almog** — August 7, 2017 at 5:23 am ([permalink](https://www.codenameone.com/blog/how-to-port-jvm-languages-to-codename-one.html#comment-23602)) + +> Shai Almog says: +> +> We don’t natively support tizen but we do support JavaScript in the enterprise tier which should work on Tizen. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-port-jvm-languages-to-codename-one.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/how-to-use-the-codename-one-sources.md b/docs/website/content/blog/how-to-use-the-codename-one-sources.md new file mode 100644 index 0000000000..3ba73fb80e --- /dev/null +++ b/docs/website/content/blog/how-to-use-the-codename-one-sources.md @@ -0,0 +1,153 @@ +--- +title: How To Use The Codename One Sources +slug: how-to-use-the-codename-one-sources +url: /blog/how-to-use-the-codename-one-sources/ +original_url: https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html +aliases: +- /blog/how-to-use-the-codename-one-sources.html +date: '2015-12-06' +author: Shai Almog +--- + +![Header Image](/blog/how-to-use-the-codename-one-sources/how-to-use-the-codename-one-sources.jpg) + +**UPDATE August 10, 2018** – The steps described in this article are out of date. The Codename One project now includes an ANT script that will retrieve dependencies and build the project automatically. [See the Quick Start section of the README](https://github.com/codenameone/CodenameOne/#quick-start-1) for instructions. + +I’ve written open source software since the 90’s both for my own projects and for Sun Microsystems. When we +founded Codename One open source was the only option! +We didn’t choose open source with +the goal of receiving code contributions. Contributions are pretty rare even in highly visible projects. We saw +the true benefits of open source for a project like Codename One: **trust**. + +When you choose a platform for your code you need to trust that it will be there tomorrow & open source +alleviates some of this risk. Open source keeps us honest about our cloud pricing. +E.g. if we overcharge or provide shoddy service a fork might gain traction. This is a benefit to the consumer +that helps us in forming trust and gaining traction in the long run. + +I felt the need to write this opening paragraph due to a highly visible source code closing done by another +company. We have no intentions, plans, thoughts or wavers in that direction. Furthermore, we consider +contributions to be the least important benefits of Open Source Software. + +Codename One is “more” open source than most projects, e.g. OpenJDK is OSS but its pretty hard to change +code within it. Its even hard to contribute these changes! +You can use/change most of our code using a trivial process. You don’t need a complex compiler toolchain +for changing or debugging Codename One. Most importantly: 99% of the code is in Java so you should feel +right at home! + +#### Using The Source + +We already have an old tutorial called “[use the source](/blog/use-the-source.html)” +but its pretty old by now. It still points at the old SVN and didn’t really go into details, so re-doing that and reminding +you that this can be done seems in order. +When you debug your app with our source code you can place breakpoints deep within Codename One and +gain unique insight. E.g. a `Form` flickers in your application just place a breakpoint in +`Display.setCurrent()`. + +When you run into a bug or a missing feature you can push that feature/fix back to us using a pull request. +Github makes that process trivial and in this new video and slides below we show you how. +The steps to use the code are: + + 1. Signup for Github + 2. Fork + and + +(also star and watch the projects for good measure). + 3. Clone the git URL’s from the projects into the IDE using the Team->Git->Clone menu option. Notice +that you must deselect projects in the IDE for the menu to appear. + 4. Download the cn1-binaries project from github [here](https://github.com/codenameone/cn1-binaries/archive/master.zip ). + 5. Unzip the cn1-binaries project and make sure the directory has the name cn1-binaries. Verify that +cn1-binaries, CodenameOne and codenameone-skins are within the same parent directory. + 6. In your own project remove the jars both in the build & run libraries section. Replace the build libraries +with the CodenameOne/CodenameOne project. Replace the runtime libraries with the +CodenameOne/Ports/JavaSEPort project. + +**Update August 10, 2018** – You will need to build the codenameone-skins project using the build.xml file in its root directory in order to generate some skins that are required to build the JavaSE project. + +This allows you to run the existing Codename One project with our source code and debug into Codename One. +You can now also commit, push and send a pull request with the changes. + +#### Video – How To Use The Codename One Sources + +#### Slides + +**[How To Use The Codename One Sources](//www.slideshare.net/vprise/how-to-use-the-codename-one-sources "How To Use The Codename One Sources") ** from **[Shai Almog](//www.slideshare.net/vprise)** +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Ch Hjelm** — June 19, 2016 at 6:15 am ([permalink](https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html#comment-22579)) + +> Ch Hjelm says: +> +> Hi, this is a great approach and I’ve used debugging of CN1 sources for quite some time. However, the video does not mention if you can build for devices using your own copy of the CN1 sources – is that possible and how should it be done? Thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-use-the-codename-one-sources.html) + + +### **Shai Almog** — June 20, 2016 at 4:10 am ([permalink](https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html#comment-22732)) + +> Shai Almog says: +> +> Building for devices is a bit more complicated so we left that as an exercise for the developers… +> +> This is actually a really difficult process to document e.g. in Android which is the simpler pipeline we run into issues all the time with Google changing things and having to run around after them. On iOS we gave the start of the process in the VM docs: [https://github.com/codename…]() but it gets pretty hairy from there on. +> +> We are looking at offering a better solution for offline building to the enterprise subscription in the near future. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-use-the-codename-one-sources.html) + + +### **Ch Hjelm** — June 20, 2016 at 9:52 pm ([permalink](https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html#comment-22675)) + +> Ch Hjelm says: +> +> Thanks for the answer. I’m not an Enterprise user (and probably never will have the budget). If you can’t build with your modified CN1 sources for a device, then isn’t what you described above useless when developing an app for a device? Unless the changes get accepted back into the code base before having to run it on a device. And you also cannot ‘hack’ the CN1 sources when needed (e.g. I’ve had to make some changes to implement specific functionality which is not likely to be accepted into your code base), making it pretty pointless to spend time trying to work around such limitations. Sorry, if I’m missing something obvious, but I think you should mention these limitations in the material above – it’s pretty frustrating to find out *after* the fact. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-use-the-codename-one-sources.html) + + +### **Shai Almog** — June 21, 2016 at 3:45 am ([permalink](https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html#comment-22934)) + +> Shai Almog says: +> +> The reason we make the enterprise requirement is because the support overhead is so great that it requires extra effort. +> +> This is step 1 of building for devices. It’s not impossible and quite a few people did that but making it too simple will cause people to try and go thru this route and running against worse walls when doing that. +> +> I’d be interested to know what sort of changes can’t be done thru a cn1lib and must go into our core sources? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-use-the-codename-one-sources.html) + + +### **AMDP AMDP** — March 23, 2017 at 12:00 pm ([permalink](https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html#comment-23130)) + +> AMDP AMDP says: +> +> “Most importantly: 99% of the code is in Java so you should feel right at home!” +> +> Just curious about the 1%. Can you describe what language and why? +> +> Troy. +> # +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-use-the-codename-one-sources.html) + + +### **Shai Almog** — March 24, 2017 at 5:33 am ([permalink](https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html#comment-23299)) + +> Shai Almog says: +> +> It’s C, C#, Objective-C & JavaScript. Each port for each OS needs native code to implement the OS abstraction layer. 99% is actually a bit high I should have said 99% of the code that matters. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-to-use-the-codename-one-sources.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/how-you-can-help-spread-codenameone.md b/docs/website/content/blog/how-you-can-help-spread-codenameone.md new file mode 100644 index 0000000000..e2aabd1c29 --- /dev/null +++ b/docs/website/content/blog/how-you-can-help-spread-codenameone.md @@ -0,0 +1,85 @@ +--- +title: How you can Help Spread Codename One +slug: how-you-can-help-spread-codenameone +url: /blog/how-you-can-help-spread-codenameone/ +original_url: https://www.codenameone.com/blog/how-you-can-help-spread-codenameone.html +aliases: +- /blog/how-you-can-help-spread-codenameone.html +date: '2016-11-29' +author: Shai Almog +--- + +![](/blog/how-you-can-help-spread-codenameone/guest-post-1.jpg) + +I’ve written this in emails before and on quite a few occasions but this bares repeating. Gaining visibility in this industry is tough especially when the industry is driven by the likes of Google, Facebook & Apple. + +Despite years of effort, most Java developers or mobile developers haven’t heard about us and it’s still an uphill battle for awareness. + +If you like our product and think we are doing something important it would be **VERY** helpful for us if you can help us with these small things. + +Doing everything below would take 5 minutes and every bit counts! + +### How Can You Help? + +If you are active on Reddit, Hackernews or any other community such as these and you think something we wrote is worthwhile for that site we’d really appreciate a share or shoutout on those sites. + +If you have accounts in any of those networks listed below, we’d appreciate the help here. + +## 🔥 List of things you can do to help Codename One grow: + + * __ Star & Fork on [GitHub](https://github.com/codenameone/CodenameOne/) + * __ Follow & Star codenameone tag on [StackOverflow](https://stackoverflow.com/tags/codenameone) + * __ Join our [Subreddit](https://www.reddit.com/r/cn1/) for open discussion & support + * __ Follow & engage on [social media](https://linktr.ee/codenameone) + * __ Download, rate & review our [app](https://play.google.com/store/apps/details?id=com.codename1.build.app) + * __ Enroll & share our courses on [Codename One Academy](https://codenameone.teachable.com/) + +### What Else? + +Community engagement for Codename One is good but it can still be better. Ask us questions on StackOverflow, fork our projects on Github, contribute your work and submit [pull requests](/blog/how-to-use-the-codename-one-sources.html). + +If you ask a proper question on StackOverflow, you will get points (which are useful when you have a really hard question), so even if it isn’t the biggest problem in the world, ask…​ + +If you see something broken, report it or submit a pull request. You can just edit the Codename One sources/docs directly on the Github site. If JavaDoc isn’t clear or the developer guide was confusing just edit them directly and help the next person coming along. The [developer guide is literally a wiki](/blog/wiki-parparvm-performance-actionevent-type.html) you can edit! + +Let us know if you have ideas how to improve the site and engage with us. Try to use the public forums e.g. comments, StackOverflow and discussion groups when engaging so other developers gain the benefits of the collective knowledge. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Hristo Vrigazov** — December 2, 2016 at 6:21 pm ([permalink](https://www.codenameone.com/blog/how-you-can-help-spread-codenameone.html#comment-24229)) + +> Hristo Vrigazov says: +> +> Codename One deserves way more visibility than it has. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-you-can-help-spread-codenameone.html) + + +### **Jaco Dt** — February 2, 2017 at 6:07 am ([permalink](https://www.codenameone.com/blog/how-you-can-help-spread-codenameone.html#comment-23138)) + +> Jaco Dt says: +> +> Agreed +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-you-can-help-spread-codenameone.html) + + +### **Francesco Galgani** — August 28, 2017 at 2:44 am ([permalink](https://www.codenameone.com/blog/how-you-can-help-spread-codenameone.html#comment-23471)) + +> Francesco Galgani says: +> +> To spread Codename One, I’m trying to encourage the Engineering students of my university to try it. I’m also added Codename One to my curriculum. Maybe I’ll also write an article about Codename One in my blog. I think that you, Shai, are doing a very important and useful job replying to almost all help requests on Stack Overflow and in this blog: your help is encouraging me in specializing in Codename One. Of course I hope that more Codename One developers will share their knowledge on StackOverflow. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhow-you-can-help-spread-codenameone.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/html-hierarchy-release-plan-teavm.md b/docs/website/content/blog/html-hierarchy-release-plan-teavm.md new file mode 100644 index 0000000000..6e8adaa802 --- /dev/null +++ b/docs/website/content/blog/html-hierarchy-release-plan-teavm.md @@ -0,0 +1,87 @@ +--- +title: HTML Hierarchy, Release Plan & TeaVM +slug: html-hierarchy-release-plan-teavm +url: /blog/html-hierarchy-release-plan-teavm/ +original_url: https://www.codenameone.com/blog/html-hierarchy-release-plan-teavm.html +aliases: +- /blog/html-hierarchy-release-plan-teavm.html +date: '2015-04-07' +author: Shai Almog +--- + +![Header Image](/blog/html-hierarchy-release-plan-teavm/html5-banner.jpg) + +When Codename One packages applications into native apps we hide a lot of details to make the process simpler. +One of the things we had an issue with is `getResource/getResourceAsStream` both of which +are problematic since they support hierarchies and a concept of package relativity. +That’s a concept that is problematic in iOS, generally everything about file access within the bundle in iOS +is a bit problematic to accomplish in a cross platform way because Apple tries so hard to “simplify” and ends +up creating fragmentation for us. + +So we have our own `getResourceAsSteam` in the `Display` class and that works +just fine, but it requires that all files be in the src root directory and still has some issues (e.g. if a file has 2 extensions). +Unfortunately there is still one major use case that’s very difficult to adapt to this usage and that is html… +Web developers are used to constructing hierarchies to represent the various dependencies and use relative +links/references. This is pretty difficult to avoid if you use pretty much any framework out there and so it was +pretty difficult to embed HTML into a Codename One application since using relative references was downright +difficult… + +We now have a solution: the html package… +Just place all of your resources in a hierarchy under the html package in the project root. Our build server will +`tar` the entire content of that package and add an html.tar file into your native package instead. +It will then untar it on the device when you actually need the resources and only with new builds (not on every launch). +So just place all your HTML’s, javascripts, images & CSS’s in the html package and the packages/directories below it. +Then you can use the web browser component like this: + + + try { + browserComponent.setURLHierarchy("/htmlFile.html"); + } catch(IOException err) { + ... + } + + +Notice that the path is relative to the html directory and starts with `/` but inside the HTML files +you should use relative (not absolute) paths. Also notice that an `IOException` can be thrown due +to the process of untarring. Its unlikely to happen but is entirely possible. + +### Codename One 3.0 + +We’ve been really bad about releasing Codename One 3.0, we wanted to do that quite a few times but +things got sidetracked with the new VM and various other issues that prevented us from reaching the point +we wanted for release. + +We decided that now is probably the best time to do it and we shouldn’t procrastinate further. Currently +the tentative release date is April 27th, but this might move based on issues. With that in mind we would +like to have a 2 week code freeze to improve stability and bring the docs up to date. So we expect to enter +code freeze on April 13th next week! This means some features/issues will be delayed to post 3.0 but we are also trying to cram as many fixes as possible +into this release and are working hard on the issue tracker. + +When we release so rarely its a big problem and makes releases harder to produce, we are now thinking of +migrating towards a Chrome/Mozilla like release schedule and release every 3 months on a fixed freeze/release +schedule. If you have thoughts on this please feel free to chime in. + +### TeaVM + +In a previous post I mentioned a Javascript VM port and this was misunderstood by some developers as +co-opting a separate open source project. Just to be clear, the work I posted about was based on +[Tea VM](http://teavm.org/) and what Steve did was mostly create a Codename One +port on top of that. Steve went into details [here](http://sjhannah.com/blog/?p=382) +in his personal blog. + +So why didn’t I just write TeaVM instead of making a generic Javascript VM statement? +We didn’t announce the product and I was not the technical guy involved, I’m neither familiar with the code +or the project/people involved so I preferred to just use a generic term. I assumed people would understand +that when we make the actual announcement/availability we will explain the technical details including the +role of TeaVM in this. + +I apologize to [Alexey](https://twitter.com/konsoletyper), I had no intention of +minimizing or reducing the credit of your effort/achievement! + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/html-maps-z-order-peer-properties-update.md b/docs/website/content/blog/html-maps-z-order-peer-properties-update.md new file mode 100644 index 0000000000..49dec8a849 --- /dev/null +++ b/docs/website/content/blog/html-maps-z-order-peer-properties-update.md @@ -0,0 +1,90 @@ +--- +title: HTML Maps, Z-Order Peer & Properties Update +slug: html-maps-z-order-peer-properties-update +url: /blog/html-maps-z-order-peer-properties-update/ +original_url: https://www.codenameone.com/blog/html-maps-z-order-peer-properties-update.html +aliases: +- /blog/html-maps-z-order-peer-properties-update.html +date: '2017-01-18' +author: Shai Almog +--- + +![Header Image](/blog/html-maps-z-order-peer-properties-update/maps.jpg) + +One of the problems with native maps is that they work very differently between the device and the simulator. This is because we use `MapComponent` on the simulator and as a fallback on the devices where Google Maps isn’t available. We just committed a new mode for maps that allows you to use the Google HTML maps as the fallback instead of the `MapComponent`. + +This is faster, has better support from Google and is more similar to the way maps work on the physical device because the browser component is also a peer component so similar restrictions will apply. This is off by default since the HTML maps require a key and right now we didn’t finish mapping all the components. This also needs some server functionality so I’m not sure when this will land in the actual extension but it’s already there is you build from source. We’ll post more about this when we do an official refresh of the extension. + +### Z-Ordering in Peer Components + +We did a lot of work getting z-ordering in Android a while back and then dropped the ball on it by postponing the rest of the work to 3.7 at the last minute. For those of you who don’t remember peer components are native OS widgets like video, browser, native maps etc. + +This change allows us to draw on top of them and place components on top of them so we can create pretty rich applications from subtitling a video to augmented reality apps would be (relatively) easy with such a change. Without this change you would need native code to do this…​ +It will also make apps that rely heavily on Native Maps far easier to write with far better results. + +Z-ordering is a big change and just didn’t fit into the schedule, however we didn’t abandon this effort and Steve just committed a major overhaul of our peer handling in the simulator/desktop port which will allow z-ordering on those platforms. + +iOS will probably be more challenging but we hope to do it sooner rather than later so we will have plenty of time to test before 3.7 lands. + +### Properties Update + +We’re working on some big changes for the `Properties` API. We added a new `MapProperty` option which is effectively a property that functions as a `java.util.Map` equivalent similar to the existing `ListProperty`. We also added properties to represent primitive or numeric types e.g. instead of writing: + + + public final Property myNumber = new Property<>("myNumber"); + +We would now write: + + + public final IntProperty myNumber = new IntProperty<>("myNumber"); + +The main motivation for this is erasure. Parsing code that accesses `myNumber` wouldn’t know the generic type since that is removed during compilation. However, we can know the type of `IntProperty` & thus implicitly convert numeric types during parsing. This isn’t as “generic” but since `NumericProperty` is a common base class for all number properties and derives from `Property` we can write common code relatively easily. + +The `NumericProperty` also introduces support for non-nullable elements in this case which will fail if you try to set a null value and thus work better with auto-boxed values. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Blessing Mahlalela** — February 16, 2017 at 11:46 am ([permalink](https://www.codenameone.com/blog/html-maps-z-order-peer-properties-update.html#comment-23303)) + +> Blessing Mahlalela says: +> +> Hi, currently trying latest Github CN1 Google maps code. I added Java script api key, however on simulator it shows Open street maps. Is it possible to display html5 JS maps on simulator and every other device that does not have the SDK? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhtml-maps-z-order-peer-properties-update.html) + + +### **Blessing Mahlalela** — February 16, 2017 at 12:12 pm ([permalink](https://www.codenameone.com/blog/html-maps-z-order-peer-properties-update.html#comment-23151)) + +> Blessing Mahlalela says: +> +> Ok, issue fixed I was using an old CN1Google lib. It will be good to remove it as it causes un necessary confusion. +> +> [https://github.com/codename…]() +> +> Secondly Android build causes an error (have not tried iOS): +> +> Exception is: +> org.gradle.api.tasks.TaskExecutionException: Execution failed for task ‘:transformClassesAndResourcesWithProguardForRelease’. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhtml-maps-z-order-peer-properties-update.html) + + +### **Shai Almog** — February 16, 2017 at 2:34 pm ([permalink](https://www.codenameone.com/blog/html-maps-z-order-peer-properties-update.html#comment-23266)) + +> Shai Almog says: +> +> This isn’t implemented completely but should work for desktop and does work for my test case. The Android build isn’t something I tested with the current version but I’ll need the full logs as this isn’t the actual error message. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fhtml-maps-z-order-peer-properties-update.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/i-am-your-density.md b/docs/website/content/blog/i-am-your-density.md new file mode 100644 index 0000000000..76f97c9cd2 --- /dev/null +++ b/docs/website/content/blog/i-am-your-density.md @@ -0,0 +1,102 @@ +--- +title: I Am Your Density +slug: i-am-your-density +url: /blog/i-am-your-density/ +original_url: https://www.codenameone.com/blog/i-am-your-density.html +aliases: +- /blog/i-am-your-density.html +date: '2015-10-20' +author: Steve Hannah +--- + +![Header Image](/blog/i-am-your-density/density-heading.jpg) + +This morning I was awoken by myself – or rather the 1985 version of myself. He (I’ll refer to the 1985 version of myself in the 3rd person here forward) was in a panic and was yammering about something to do with changing history. He asked why my pants were inside out, and I wondered why he was wearing a life preserver. According to him, he had driven a time machine from 1985 to this day (October 21, 2015) in the future to stop me from making a terrible mistake. I asked him: “What mistake?”, to which he produced a 3.5 inch floppy disk. + +“On this disk, you’ll find a scan of a single page from a Grays Sports Almanac, that displays the score to the 2015 world series”. He implored me to look at the image and use it to change the team that I had planned to bet on. No sooner did I take the disk from him, than he made like a tree and got out of there. + +The first hurdle to viewing this image was in loading it off of that floppy disk in this post floppy disk world. I wasn’t going to let that stop me, though. If you put your mind to it, you can accomplish anything. + +After some struggles, I managed to copy the image from the floppy disk onto my cell phone so I could view it. Unfortunately, the image was too small to make anything out. The image itself, he had said was 1 inch by 1 inch. But on my phone, it only rendered at a measly 8th of an inch. It basically looked like a speck on my screen. + +What the??! He said it was 1 inch squared. How will I ever see what is on this image? I soon realized that the problem was that I wasn’t thinking 4th dimensionally: the fourth dimension being density. My 1985 self was using a Macintosh of the time that had a pixel density of approximately 57 pixels per inch. My cell phone, on the other hand was a new iPhone 6+, with a pixel density of about 480 pixels per inch. So his 57×57 pixel image looked fine on his old screen, but was only an eighth of an inch on mine. Heavy! Device displays in the future are too dense to display this image at a reasonable size. + +What I needed to do was convert this image to a multi-image so that it would display at the proper size on my device, and all devices. So I imported the image into my Codename One resource file, specifying a source density of “Very Low”. Then created a simple app using the Codename One GUI builder, that displays a single label. The source to display the multi-image roughly as follows (Please excuse the crudity of this model. I didn’t have time to build it to scale or paint it): + + + System.out.println("I'm your density: "+ Display.getInstance().getDeviceDensity()); + + Label image = new Label(theme.getImage("AlmanacClipping.png")); + theForm.addComponent(image); + +Since the image is a multi-image, the app should display it at the correct “real” size of 1 inch by 1 inch. + +After loading the app onto my phone, I can finally see the message: “Chicago Cubs win the World Series!”. + +![925d0d00 77ea 11e5 8b1b dee46a613a54](/blog/i-am-your-density/925d0d00-77ea-11e5-8b1b-dee46a613a54.png) + +Hmm. Good thing I didn’t bet on the Blue Jays, as I had planned to do. On the bright side, my app works. It displays the image in the correct size on all devices. I finally invent something that works! Perhaps I should submit this to the iTunes store and Google Play. + +But what if I send in the app in and they don’t like it? What if they say I’m no good? What if they say, “Get out of here kid. You’ve got no future”? I mean, I just don’t think I can take that kind of rejection. + +## Behind the Scenes: The Making of this Post + +The iPhone 3gs has a 3.5″ display with a resolution of 320×480, which works out to approximately 163 pixels per inch across both the horizontal and vertical axes. + +The iPhone 4 also has a 3.5″ display, but the resolution is double: 640×960, which works out to approximately 326 pixels per inch across the horizontal and vertical axes. + +Therefore, if you render a 163×163 pixel image on an iPhone 3Gs the result will be approximately 1 inch squared in the real world. The same image rendered on an iPhone 4 would be approximately 0.5 inches squared – or half the size. Similarly font sizes, border thickness, padding, margins, and positions specified in pixels will produce different results on an iPhone 3Gs than on an iPhone 4. + +This is just a small sample from a vast sea of different device densities that are available on the market. I use this example to demonstrate one of the inherent challenges in writing cross-platform user interfaces. Luckily, Codename One provides you with the tools you need to work in a multi-device world. + +### Device Densities + +At runtime, you can always find the host device’s approximate pixel density using the `Display.getDeviceDensity()` method. This will return one of: + +Constant | Density | Example Device +---|---|--- +`Display.DENSITY_VERY_LOW` | ~ 88 ppi | +`Display.DENSITY_LOW` | ~ 120 ppi | Android ldpi devices +`Display.DENSITY_MEDIUM` | ~ 160 ppi | iPhone 3GS, iPad, Android mdpi devices +`Display.DENSITY_HIGH` | ~ 240 ppi | Android hdpi devices +`Display.DENSITY_VERY_HIGH` | ~ 320 ppi | iPhone 4, iPad Air 2, Android xhdpi devices +`Display.DENSITY_HD` | ~ 540 ppi | iPhone 6+, Android xxhdpi devices +`Display.DENSITY_560` | ~ 750 ppi | Android xxxhdpi devices +`Density.DENSITY_2HD` | ~ 1000 ppi | +`Density.DENSITY_4K` | ~ 1250ppi | + +### Multi-Images + +In 99% of cases, you’ll want images to render at the same “real” size on all devices, rather than their pixel size. Codename One has you covered here with its multi-image support. You can import an image into the resource file, specifying its source density, and it will be embedded at all of the densities that you specify. Then you can obtain a reference to the image using the `Resources.getImage()` method at runtime, it will give the correct version of the image for the device’s density so that the “real” size of the image will be preserved across all devices. + +### Use Millimetres, Not Pixels for Dimensions + +When configuring your styles, you should almost never use “Pixels” as the unit for padding, margins, font size, and border thickness because the results will be inconsistent on different densities. Instead, you should use millimetres for all non-zero units of measurements. + +#### Fractions of Millimetres + +Sometimes millimetres don’t give you enough precision for what you want to do. Currently the resource editor only allows you to specify integer values for most units. However, you can achieve more precise results when working directly in Java. The `Display.convertToPixels()` method will allow you to convert millimetres (or dips) to pixels. It also only takes an integer input, but you can use it to obtain a multiplier that you can then use to convert any millimeter value you want into pixels. + +E.g. + + + double pixelsPerMM = ((double)Display.getInstance().convertToPixels(10, true)) / 10.0; + +And now you can set the padding on an element to 1.5mm. E.g. + + + myButton.getAllStyles().setPaddingUnit(Style.UNIT_TYPE_PIXELS); + int pixels = (int)(1.5 * pixelsPerMM); + myButton.getAllStyles().setPadding(pixels, pixels, pixels, pixels); + +### Font Sizes + +If you’re using system fonts (the default), then you’re limited to only three font sizes: Small, Medium, and Large. These will be converted to an appropriate “real” size on the device. If you need more precision, you can embed a TTF font with your app, then you can specify font size in millimetres (or DIPS). And if you require more precision on the font size than millimetres, you can use the same trick above to obtain a fractional millimetres to pixels conversion, and use the `Font.deriveFont()` method to generate a font in the exact “real” size that you desire. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/icon-fonts-oldvm-swan-song.md b/docs/website/content/blog/icon-fonts-oldvm-swan-song.md new file mode 100644 index 0000000000..6ca41fa7d6 --- /dev/null +++ b/docs/website/content/blog/icon-fonts-oldvm-swan-song.md @@ -0,0 +1,71 @@ +--- +title: Icon Fonts & Old VM Swan Song +slug: icon-fonts-oldvm-swan-song +url: /blog/icon-fonts-oldvm-swan-song/ +original_url: https://www.codenameone.com/blog/icon-fonts-oldvm-swan-song.html +aliases: +- /blog/icon-fonts-oldvm-swan-song.html +date: '2015-06-23' +author: Shai Almog +--- + +![Header Image](/blog/icon-fonts-oldvm-swan-song/font-awesome.jpg) + +While multi-image’s go a long way in making your app scalable to various devices, scalable images can be even +more convenient. The SVG standard never took off though, its too complex to support in an efficient way on +the devices and so its relegated to web applications and even those don’t make heavy use of it due to its complexity. +However, icon fonts have gained a lot of popularity in recent years and we used them in the past in Codename One +e.g. in the [photo demo](http://udemy.com/build-mobile-ios-apps-in-java-using-codename-one/). + +That usage was awkward, we had to define a special font for the tab area and use letters in a way that didn’t communicate +what would actually appear on the screen. It worked because we only used an icon without text, had we tried to use +both it wouldn’t have worked… +So we now have support for icon fonts via the new `FontImage` class. This class encapsulates a character +or string from the icon font and presents it as an image. You can even scale and rotate such as image and you can convert +it to an `EncodedImage` or regular `Image` if necessary. + +This allows very smooth graphics that adapt based on the platform e.g. here we use the fontello font to show a rotating +progress wheel, thanks to the smoothness of the font the progress looks far more refined: + + + InfiniteProgress ip = new InfiniteProgress(); + int size = Display.getInstance().convertToPixels(20, true); + Font fnt = Font.createTrueTypeFont("fontello", "fontello.ttf"); + FontImage fm = FontImage.createFixed("ue800", fnt, 0xffffff, size, size); + ip.setAnimation(fm); + ip.showInifiniteBlocking(); + +We can create such an image using two methods, a fixed size/color image which you can use to assign a pixel +size for such an image and a more “generic” method that will accept a style and adapt the icon for that style. + +As we move forward we would like to integrate icon fonts far deeper into the Codename One stack, this would +include integration with the designer tools etc. + +#### Retiring The Old VM + +Apple is pretty quick with with moving forward, they pushed everyone to 64 bit very fast and it seems they are +poised to do the same with some new iOS 9 changes. This usually takes the form of requiring an xcode upgrade +which is pretty easy for us to do since we just need to login to all the servers and update xcode on those machines. + +This does pose a problem though, the newer versions of xcode require a newer version of Mac OS (Yosemite or even newer), +unfortunately the older versions of xcode that still run the old VM don’t work on Yosemite anymore and aren’t +maintained by Apple. We will try to wait until the last minute to upgrade in order to allow those of you who +are still building with the old VM (e.g. in the enterprise setting) some time to migrate. However, you must migrate… +Even versioned builds won’t work with the old VM once the OS is updated so you can no longer rely on the old +XMLVM builds to still work in the future! + +Unfortunately some of our enterprise users just don’t read the blog, social media posts or our repeated mailings on the subject… +Which is why we will be retiring the `ios.newVM` build hint so those guys who just added it and forgot +about it will be **forced** to re-evaluate its necessity. + +We will expose a new flag: `ios.deprecatedDontUseThisFlagSeriouslyOldVM` which you can set to true +to force the old vm. But seriously… +**Don’t use it**. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/icon-fonts-popups-infinite-scroll.md b/docs/website/content/blog/icon-fonts-popups-infinite-scroll.md new file mode 100644 index 0000000000..13ce09ecfa --- /dev/null +++ b/docs/website/content/blog/icon-fonts-popups-infinite-scroll.md @@ -0,0 +1,114 @@ +--- +title: Icon Fonts, Popups and Infinite Scroll +slug: icon-fonts-popups-infinite-scroll +url: /blog/icon-fonts-popups-infinite-scroll/ +original_url: https://www.codenameone.com/blog/icon-fonts-popups-infinite-scroll.html +aliases: +- /blog/icon-fonts-popups-infinite-scroll.html +date: '2019-09-06' +author: Shai Almog +--- + +![Header Image](/blog/icon-fonts-popups-infinite-scroll/new-features-1.jpg) + +As I mentioned in the last post there are a lot of new features we need to go over and it will take time to cover everything. In fact this is still a partial list and there’s a lot more on the way…​ + +### Easier Icon Font Integration + +First off [Thomas](https://github.com/ThomasH99) [submitted a PR](https://github.com/codenameone/CodenameOne/issues/2856) for a few new font icon methods: + +Specifically in `Label` he added: + + + public void setFontIcon(Font font, char c); + public void setFontIcon(Font font, char c, float size); + +And in `FontImage` he added: + + + public static void setFontIcon(Label l, Font font, char icon, float size); + public static void setFontIcon(Label l, Font font, char icon); + public static void setFontIcon(Command c, Font font, char icon, String uiid, float size); + +These new methods work in a similar way to the set material icon methods. However, they can work with an arbitrary icon font. That was possible to do before this change but this change makes that easier and makes the code more fluid. It also works similarly to the material API where icons are implicitly applied to all the states of the buttons. That means the pressed/selected/disabled styles will apply to the icon as well as the text. + +### Additional Icon Fonts + +[Francesco Galgani](https://github.com/jsfan3) came up with a solution for [#2421](https://github.com/codenameone/CodenameOne/issues/2421) which finally allowed us to update the material font and font constants. + +This has been a long time RFE which came up every few months. When we launched the material font support. Unfortunately, Google stopped updating that font a few years ago and everyone who relied on it was stuck. Thankfully Francesco found an up to date version of the font as well as the diffs between the old/new font. + +As a result we now have a lot more constants you can use when setting an icon in a default Codename One app. You can see the full list [here](https://github.com/codenameone/CodenameOne/commit/a826eac206062b52391480396884e3b4e5fa5f86). + +### Lightweight Popup Dialog + +When Codename One was young we needed a popup arrow implementation but our low level graphics API was pretty basic. As a workaround we created a version of the 9-piece image border that supported pointing arrows at a component. + +Since we added a proper graphics pipeline we wanted to rewrite that logic to use proper graphics. This allows for better customization of the border (color, shape etc.) and it looks better on newer displays. It also works on all OSs. Right now only the iOS theme has the old image border approach. + +To solve this we [added new support for arrows](https://github.com/codenameone/CodenameOne/commit/921395f6613e7a2bb883f41d4217797f7d790fa9) into the `RoundRectBorder` API. If you style a popup dialog with a round rect border this should “just work” and use this API. By default popup dialogs are styled that way with the exception of iOS where they still have the image border styling for compatibility (although we might change that). + +This works by setting the track component property on border. When that’s done the border implicitly points to the right location. + +### Continue the Infinite + +`InfiniteContainer` and `InfiniteAdapter` work great for most use cases but they have a bit of an [“undefined” behavior when it comes to failure](https://github.com/codenameone/CodenameOne/issues/2721). E.g. if we have a network error and don’t have anything to fetch as a result. + +to solve this we added this method to `InfiniteContainer`: + + + public void continueFetching(); + +And these to `InfiniteScrollAdapter`: + + + public void continueFetching(); + public static void continueFetching(Container cnt); + +So when you get an error you can just add this error button and return null: + + + SpanButton errorButton = new SpanButton("Networking Error, Press to retry"); + errorButton.addActionListener(e -> { + errorButton.remove(); + continueFetching(); + }); + add(errorButton); + return null; + +The error button will let the user retry the operation and continue fetching the content even though it was previously “stopped”. + +### More Coming + +As I mentioned at the top of this post, this is still the tip of the iceberg of new features we’ve worked on over the summer. More is coming! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — September 14, 2019 at 8:23 am ([permalink](https://www.codenameone.com/blog/icon-fonts-popups-infinite-scroll.html#comment-24090)) + +> Francesco Galgani says: +> +> I’ve just tested that a Popup Dialog works fine also with an Android skin, thank you! About the Popup Dialog, isn’t the developer guide section “Styling The Arrow Of The Popup Dialog” more valid? Should this part of the developer guide be changed? Link: [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ficon-fonts-popups-infinite-scroll.html) + + +### **Shai Almog** — September 15, 2019 at 3:44 am ([permalink](https://www.codenameone.com/blog/icon-fonts-popups-infinite-scroll.html#comment-23825)) + +> Shai Almog says: +> +> Thanks, I updated that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Ficon-fonts-popups-infinite-scroll.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/image-from-url-made-easy.md b/docs/website/content/blog/image-from-url-made-easy.md new file mode 100644 index 0000000000..e29bdc8b68 --- /dev/null +++ b/docs/website/content/blog/image-from-url-made-easy.md @@ -0,0 +1,295 @@ +--- +title: Image From URL Made Easy +slug: image-from-url-made-easy +url: /blog/image-from-url-made-easy/ +original_url: https://www.codenameone.com/blog/image-from-url-made-easy.html +aliases: +- /blog/image-from-url-made-easy.html +date: '2014-03-02' +author: Shai Almog +--- + +![Header Image](/blog/image-from-url-made-easy/image-from-url-made-easy-1.png) + + + + + +![Picture](/blog/image-from-url-made-easy/image-from-url-made-easy-1.png) + + + + +ImageDownloadService is one of the first classes we wrote when creating the original IO package, as such we were still thinking over the API and the code… stinks. + + +I’ve had the task of writing a tutorial for ImageDownloadService for such a long time and I just kept procrastinating on it because it is so painful to deal with. Eventually I broke down and decided to solve the problem in the proper way of creating a completely new API that’s simpler and thus doesn’t really require an extensive tutorial: URLImage. + + + + +URLImage is an image created with a URL… Simple. It is seamlessly downloaded, scaled (adapted) and automatically updates itself in place. All good. + + + + +The simple use case is pretty trivial: + + +Image i = URLImage.createToStorage(placeholder, “fileNameInStorage”, “http://xxx/myurl.jpg”, URLImage.RESIZE_SCALE); + + + + +Alternatively you can use the similar + + + + + + + + +URLImage.createToFileSystem method instead of the Storage version. + + + +This image can now be used anywhere a regular image will appear, it will initially show the placeholder image and then seamlessly replace it with the file after it was downloaded and stored. + + +Notice: Since + +ImageIO is used to perform the operations of the adapter interface its required that ImageIO will work. It is currently working in JavaSE, Android, iOS & Windows Phone. It doesn’t work on J2ME/Blackberry devices so if you pass an adapter instance on those platforms it will probably fail to perform its task. + + + + +If the file in the URL contains an image that is too bit it will scale it to match the size of the placeholder precisely! + + + +We currently also have an option to fail if the sizes don’t match. Notice that the image that will be saved is the scaled image, which means you will have very little overhead in downloading images that are the wrong size although you will get some artifacts. + + + + + +The last argument is really quite powerful, its an interface called URLImage.ImageAdapter and you can implement it to adapt the downloaded image in any way you like. E.g. you can use an image mask to automatically create a rounded version of the downloaded image or to scale based on aspect ratio. We will probably add some tools to implement such functionality based on user demand. + + + + +To do this you just override public EncodedImage adaptImage(EncodedImage downloadedImage, Image placeholderImage) in the adapter interface and just return the processed encoded image. If you do heavy processing (e.g. rounded edge images) you would need to convert the processed image back to an encoded image so it can be saved. You would then also want to indicate that this operation should run asynchronously via the appropriate method in the class. + + + + +If you need to download the file instantly and not wait for the image to appear before download initiates you can explicitly invoke the fetch() method which will asynchronously fetch the image from the network. + + + + + + +** +Lists +** + + +The biggest problem with image download service is with lists. We decided to attack this issue at the core by integrating URLImage support directly into GenericListCellRenderer which means it will work with MultiList, List & ContainerList. To use this support just define the name of the component (name not UIID) to end with _URLImage and give it an icon to use as the placeholder. This is easy to do in the multilist by changing the name of icon to icon_URLImage then using: + + +map.put(“icon_URLImage”, urlToActualImage); in the data. + + +Make sure you also set a “real” icon to the entry in the GUI builder or in handcoded applications. This is important since the icon will be implicitly extracted and used as the placeholder value. Everything else should be handled automatically. You can use setDefaultAdapter & setAdapter on the generic list cell renderer to install adapters for the images. The default is a scale adapter although we might change that to scale fill in the future. + + + + + + + + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — March 14, 2014 at 7:15 am ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-21869)) + +> Anonymous says: +> +> Thanks, this is just what I needed for my new project! That old ImageDownloadService worked as well, but it surely felt a bit clumsy. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — April 4, 2014 at 12:27 am ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-22066)) + +> Anonymous says: +> +> Hi, i want to use the URLImage class in my current project but can’t seem to find it in my current version of codenameone running on netbeans 7.4. How do I incorperate it into my IDE? I tried downloading the latest plugin but it did not do the job. Any tips? As I find the ImageDownloadService confusing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — April 4, 2014 at 2:57 am ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-21913)) + +> Anonymous says: +> +> Libraries are updated by going to the project properties Codename One section and clicking the update client libs button. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — April 4, 2014 at 9:12 am ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-22049)) + +> Anonymous says: +> +> Thanks for the prompt response! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — April 4, 2014 at 10:34 am ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-21976)) + +> Anonymous says: +> +> Hi Shai, I tested between two seperate image urls (via simulator) and noticed that unless the “fileNameInStorage” is changed, the image displayed will not change despite the url used. This likely means that the image is stored locally and is no longer being called via the URL. +> +> I would like to know if the images that are downloaded via the URL are stored in a directory and if so where? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — April 4, 2014 at 3:46 pm ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-21992)) + +> Anonymous says: +> +> All images are placed in Storage or FileSystemStorage based on the type of URL you created under the file name you gave. Storage and file system are mapped to the .cn1 directory in your home directory for the simulator. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — June 19, 2014 at 5:47 am ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-22114)) + +> Anonymous says: +> +> Hi Shai, +> +> This seems very convenient in most case. +> +> I have 2 questions: +> +> – what about background pictures ? +> +> – is there anylimitations we should be aware of (like only PNG files, max size file, resolution) ? +> +> Thank you. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — June 20, 2014 at 12:46 am ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-21675)) + +> Anonymous says: +> +> Hi, +> +> background images should work too. +> +> Any file type should work although if the image is rescaled using the default scaling in some cases the image will become a PNG and in others it will become a JPEG. The logic isn’t as clear as it should be. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — June 20, 2014 at 10:00 am ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-22143)) + +> Anonymous says: +> +> Hi. +> +> I am not able to work with URLImage for background pictures. +> +> Also, I have done a dumb test. I try to insert 4000 pictures downloaded inside my form. +> +> When pictures are downloaded, scroll is smooth and efficient. +> +> But, when app is downloading pictures, and during this time, we have a bad scroll effect on Android device (Nexus 4). But not on iOS. +> +> Any idea ? +> +> Thank you. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — June 20, 2014 at 1:53 pm ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-24238)) + +> Anonymous says: +> +> 4000 seems like a bit much. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — June 21, 2014 at 4:20 pm ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-21848)) + +> Anonymous says: +> +> Thank you for your answer Shai. +> +> I agree, 4000 is quite too much. But I have the same result with 400. +> +> And I do not get the difference between Android and iOS. +> +> Is there something I can / should do ? +> +> I read on the forum other option like pre-download the pictures in the background and I will use it anyway. But if I can do something on this case, it would be great. +> +> Thank you. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — March 3, 2015 at 6:31 am ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-22148)) + +> Anonymous says: +> +> How can I fetch changing placeholder image by downloaded image for revalidate ImageViewer? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + + +### **Anonymous** — March 3, 2015 at 12:19 pm ([permalink](https://www.codenameone.com/blog/image-from-url-made-easy.html#comment-22178)) + +> Anonymous says: +> +> I don’t quite understand the question but did you see the property cross demo and tutorial where we use this API in two different settings: +> +> [http://www.codenameone.com/…]() +> +> [https://www.udemy.com/learn…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fimage-from-url-made-easy.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/image-overriding.md b/docs/website/content/blog/image-overriding.md new file mode 100644 index 0000000000..010b6f74e5 --- /dev/null +++ b/docs/website/content/blog/image-overriding.md @@ -0,0 +1,105 @@ +--- +title: Image Overriding +slug: image-overriding +url: /blog/image-overriding/ +original_url: https://www.codenameone.com/blog/image-overriding.html +aliases: +- /blog/image-overriding.html +date: '2016-08-17' +author: Shai Almog +--- + +![Header Image](/blog/image-overriding/clock-image.gif) + +I hoped todays post would cover the new Kitchen Sink demo but due to a couple of bugs we decided to postpone that to next week. In the meantime I’d like to discuss something I did there which is actually pretty cool and most developers have no idea that we can do: Image Overriding. + +The new kitchen sink renders a set of icons like the old demo. In this version of the demo we wanted to show off graphics drawing which is an important feature missing from the old demo. Steve’s clock demo is a great example of that! + +When the time came to create an icon for that demo it dawned on us that it would be cool if the clock icon was actually “live”. We decided to create an `Image` in code that draws everything dynamically. Yes, we could have used a `Painter` but that would have meant reworking a lot of the existing code, the same would have been true if we used another component. + +This is the code we used to create a clock, I’m redacting the clock drawing code itself for brevity’s sake: + + + class ClockImage extends Image { + int w = 250, h = 250; + + ClockImage() { + super(null); + } + + ClockImage(int w, int h) { + super(null); + this.w = w; + this.h = h; + } + + @Override + public int getWidth() { + return w; + } + + @Override + public int getHeight() { + return h; + } + + @Override + public void scale(int width, int height) { + w = width; + h = height; + } + + @Override + public Image fill(int width, int height) { + return new ClockImage(width, height); + } + + @Override + public Image applyMask(Object mask) { + return new ClockImage(w, h); + } + + + @Override + public boolean isAnimation() { + return true; + } + + @Override + public boolean requiresDrawImage() { + return true; + } + + @Override + protected void drawImage(Graphics g, Object nativeGraphics, int x, int y) { + paintClock(g, x, y, w, h, x + g.getTranslateX(), y + g.getTranslateY()); + } + + @Override + protected void drawImage(Graphics g, Object nativeGraphics, int x, int y, int w, int h) { + paintClock(g, x, y, w, h, x + g.getTranslateX(), y + g.getTranslateY()); + } + + @Override + public boolean animate() { + if (System.currentTimeMillis() / 1000 != lastRenderedTime / 1000) { + currentTime.setTime(System.currentTimeMillis()); + return true; + } + return false; + } + }; + +That is it! + +Notice that the image must declare itself as an animation and then override `animate()` to invoke `drawImage`. Also notice the method `requiresDrawImage` which disables some builtin image optimizations that we can perform in the native layer that might break this. + +This is how we built `FontImage` within our code and we might do more of this as we move forward to allow more vector graphics primitives. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/image-viewer-from-the-web.md b/docs/website/content/blog/image-viewer-from-the-web.md new file mode 100644 index 0000000000..5729cfb70e --- /dev/null +++ b/docs/website/content/blog/image-viewer-from-the-web.md @@ -0,0 +1,56 @@ +--- +title: Image Viewer From The Web +slug: image-viewer-from-the-web +url: /blog/image-viewer-from-the-web/ +original_url: https://www.codenameone.com/blog/image-viewer-from-the-web.html +aliases: +- /blog/image-viewer-from-the-web.html +date: '2014-08-19' +author: Shai Almog +--- + +![Header Image](/blog/image-viewer-from-the-web/image-viewer-from-the-web-1.png) + + + + + +![Picture](/blog/image-viewer-from-the-web/image-viewer-from-the-web-1.png) + + + + +I’ve been working on demos for JavaZone and built something small that has been asked a few times. Some developers were looking for +[ +URLImage +](http://www.codenameone.com/3/post/2014/03/image-from-url-made-easy.html) +support in image viewer but that’s not a very good approach since URLImage expects images to be at a specific resolution and is thus very bad for images with unknown dimensions. However, ImageViewer thrives on showing and zooming full sized images. + + +There was a bit of a community hack with ImageDownloadService a while back but it was a bit in-elegant and wasn’t + +what I was looking for, so I created a simple list model that just streams images, you can use it with image viewer like this: + + +ImageViewer viewer = new ImageViewer(imageList.getItemAt(offset)); + +viewer.setImageList(imageList); + + +The list model is just a plain old list model that expects the placeholder image to be an encoded image you have already loaded. This implementation expects images to have an ID which we use in the createImageURL method. Notice we could just use the image index but since that might change (user deletes images etc.) we needed to have ID’s generated by the server. We’ll have the full demo up with the server side code for JavaZone: + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/improved-background-behavior.md b/docs/website/content/blog/improved-background-behavior.md new file mode 100644 index 0000000000..6f095eb767 --- /dev/null +++ b/docs/website/content/blog/improved-background-behavior.md @@ -0,0 +1,34 @@ +--- +title: Improved Background Behavior +slug: improved-background-behavior +url: /blog/improved-background-behavior/ +original_url: https://www.codenameone.com/blog/improved-background-behavior.html +aliases: +- /blog/improved-background-behavior.html +date: '2016-08-15' +author: Shai Almog +--- + +![Header Image](/blog/improved-background-behavior/background-fetch.jpg) + +A couple of years ago at Google IO one of the prominent speakers turned to the audience and asked them: “Raise your hands if you understand the activity lifecycle”. He then proceeded to call them “liars”, claiming that after all his years at Google he still doesn’t get it properly…​ + +As a guy who worked on VM’s and understands some of the nuance I totally get his point. Lifecycle is hard. On Android it seems the developers took a difficult subject and made it even harder. With that in mind our implementation of background behavior on Android was lacking in some regards and Steve did a major overhaul of the implementation. Like all overhauls this could trigger some regressions so please keep your eyes open for such cases. + +This change should be seamless and improve the applications robustness if you use background features. + +### Material Icons Everywhere + +This went in a while back, we now use material icons in the `MediaPlayer` class by default for play/pause/forward & back. + +We will also default to using material icons to represent tree folders/nodes in the next update to make it better looking and consistent by default. + +We hope to use material icons by default on all UI elements. Getting to the older pieces of code is sometimes challenging as we don’t always notice them. If you can think of a component that can use a material icon makeover sound off in the comments. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/improving-the-ios-port-moving-to-full-java-5-support.md b/docs/website/content/blog/improving-the-ios-port-moving-to-full-java-5-support.md new file mode 100644 index 0000000000..ee3d1829d0 --- /dev/null +++ b/docs/website/content/blog/improving-the-ios-port-moving-to-full-java-5-support.md @@ -0,0 +1,57 @@ +--- +title: Improving The iOS Port – Moving To Full Java 5 Support +slug: improving-the-ios-port-moving-to-full-java-5-support +url: /blog/improving-the-ios-port-moving-to-full-java-5-support/ +original_url: https://www.codenameone.com/blog/improving-the-ios-port-moving-to-full-java-5-support.html +aliases: +- /blog/improving-the-ios-port-moving-to-full-java-5-support.html +date: '2013-06-19' +author: Shai Almog +--- + +![Header Image](/blog/improving-the-ios-port-moving-to-full-java-5-support/improving-the-ios-port-moving-to-full-java-5-support-1.png) + + + + + +![Duke](/blog/improving-the-ios-port-moving-to-full-java-5-support/improving-the-ios-port-moving-to-full-java-5-support-1.png) + + + + +We constantly try to improve the performance, speed and build speed of the various ports most importantly the iOS port. + + + + +[ +Steve +](http://sjhannah.com/blog/?p=229) +found out a while back during his investigations that the synchronized keyword is especially slow in our iOS port, this is something that isn’t trivial to fix in the port itself. I made some work the past couple of days of mitigating the problem by adding usages of a StringBuilder like class and removing synchronization (which never worked anyway) from TextArea. This provided very dramatic and noticeable performance improvements on iOS. + + +The next thing to do would be to remove the usage of Vector/Hashtable for MUCH faster performance by moving to ArrayList/HashMap both of which are unsynchronized and should boost performance on all devices. + + +Why didn’t we just “do it”? + + +The main issue is compilability, + +our open source code is compileable on all the platforms we support. But for J2ME/Blackberry this is a bit difficult since our server does quite a bit of heavy lifting. So our goal is to try and place the code that allows translating J2ME/Blackberry code to Java5 into the open source and then start moving forward with proper Java 5 support in the core project. + + +I hope we can start doing this soon. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/in-a-pinch.md b/docs/website/content/blog/in-a-pinch.md new file mode 100644 index 0000000000..1757990448 --- /dev/null +++ b/docs/website/content/blog/in-a-pinch.md @@ -0,0 +1,238 @@ +--- +title: In A Pinch +slug: in-a-pinch +url: /blog/in-a-pinch/ +original_url: https://www.codenameone.com/blog/in-a-pinch.html +aliases: +- /blog/in-a-pinch.html +date: '2013-08-06' +author: Shai Almog +--- + +![Header Image](/blog/in-a-pinch/in-a-pinch-1.jpg) + + + + + +![Picture](/blog/in-a-pinch/in-a-pinch-1.jpg) + + + + +Codename One has supported multi-touch and effectively pinch to zoom events from the very first release. However, it wasn’t intuitive to write code that would handle pinch to zoom. We just committed new pinch callback events to component which effectively allows you to zoom in/out with gestures. + + + + + +Effectively if you are interested in handling pinch you would just override: + +protected boolean pinch(float scale) and return true after handling the pinch operation. We did this to support our new +[ +ImageViewer class +](http://code.google.com/p/codenameone/source/browse/trunk/CodenameOne/src/com/codename1/components/ImageViewer.java) +(where you can see a working sample of pinch), the image viewer allows you to inspect, zoom and pan into an image. It also allows swiping between images if you have a set of images (using an image list model). + + +Now to simulate the pinching we needed a simpler solution than just building for the device, which is why we added right click dragging. Now when you drag using the right mouse button (or by pressing 2 fingers on a Mac laptop and dragging together) you will get a pinch effect. We do this by hardcoding the second finger at position 0,0. So effectively if you drag towards the top left corner you will be zooming out (fingers closer together) and by dragging away you will be zooming in. + +Here is a simple example of using the ImageViewer: + +* * * + +Notice that we use a list to allow swiping between images (unnecessary if you have only one image), we also create a placeholder image to show while the image is still loading. Notice that encoded images aren’t always fully loaded and so when you swipe if the images are really large you might see delays! + + + + +This leads me to one of the more important aspects here: image locking. + +** + +Image Locking + +** + + + + +Once of the big performance improvements we got in swiping was through image locking, unfortunately this is so unclear in our current docs that when Nokia forked LWUIT they actually removed the usage of EncodedImage instead of fixing a minor locking bug. + + + +To understand locking we first need to understand EncodedImage. EncodedImage stores the data of the image in RAM (png or JPEG data) which is normally pretty small, unlike the full decoded image which can take up to width X height X 4. When a user tries to draw an encoded image we check a WeakReference cache and if the image is cached then we show it otherwise w + +e load the image, cache it then draw. + + +Naturally loading the image is more expensive so we want the images that are showing to stay in cache (otherwise GC will thrash a lot). + +That’s where lock() kicks in, we automatically invoke image loading when necessary but when lock() is active we keep a hard reference to the actual native image so it won’t get GC’d. + +This REALLY + +improves performance! + + +Internally we invoke this automatically for bg images, icons etc. which results in a huge performance boost. However, if you use a complex renderer or custom drawing UI you should lock() your images where possible! + + + + + +** + + +Generics Update +** + +You might have noticed from the code above that the list model is now generified, the same is also true now for the list renderer and list. We are working on modernizing as much of our code as we can while maintaining backwards compatibility. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — August 12, 2013 at 8:28 am ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-21826)) + +> Anonymous says: +> +> This is one of missing APIs,what I am waiting for. Great!! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + + +### **Mahmoud** — April 3, 2016 at 7:35 am ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-22797)) + +> Mahmoud says: +> +> dear shai +> i have dynamic list in ImageViewer( images from url) +> i want to swipe images not on touch only but in pressing button too (swiping left and right) +> how can i do it +> +> thanks, +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + + +### **Shai Almog** — April 4, 2016 at 2:30 am ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-22808)) + +> Shai Almog says: +> +> Hi, +> there is a code sample within the JavaDocs that covers just that use case: [https://www.codenameone.com…]() +> It’s also included in the developer guide section of the ImageViewer: +> [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + + +### **Mahmoud** — April 5, 2016 at 8:11 am ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-22492)) + +> Mahmoud says: +> +> hi Shai, +> thank you … +> i use setSelectedIndex method in ImageList +> int myNewIndex=myImageViewer.getImageList().getSelectedIndex()(+1 or -1); to swiping left and right +> and +> myImageViewer.getImageList().setSelectedIndex(myNewIndex); +> +> BR, +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + + +### **Mahmoud** — June 25, 2016 at 1:24 am ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-22758)) + +> Mahmoud says: +> +> dear shai, +> i have ImageViewer the image size 800X400 +> +> when i run my app on small device the image looks like attached image (there’s a space on top and bottom of image ) +> any idea please +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + + +### **Shai Almog** — June 25, 2016 at 5:56 am ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-22624)) + +> Shai Almog says: +> +> Images default to “scale to fit” in the image viewer. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + + +### **Mahmoud** — June 25, 2016 at 11:05 pm ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-21519)) + +> Mahmoud says: +> +> ok how i can change it +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + + +### **Shai Almog** — June 26, 2016 at 4:48 am ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-22800)) + +> Shai Almog says: +> +> You can change the zoom level, but are you trying to show a static image or allow the user to change that? If the former then image viewer is the wrong component to use. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + + +### **Mahmoud** — June 26, 2016 at 7:13 am ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-22851)) + +> Mahmoud says: +> +> dynamic list in ImageViewer( images from url) i show it as slider +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + + +### **Shai Almog** — June 27, 2016 at 3:06 am ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-22860)) + +> Shai Almog says: +> +> So if you have multiple images in the viewer and flip between them zooming in will be a mistake. +> This can create an image whose edges are wider than the screen so when you try to swipe you will really pan within the image… +> You can replicate that behavior by zooming in with pinch and trying to swipe to see what I mean. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + + +### **Mahmoud** — July 1, 2016 at 4:09 pm ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-22901)) + +> Mahmoud says: +> +> i have list of images not multi-images and i have Image Viewer +> if you understand what i mean , is any way to create slider images without space on top and bottom of image in small device +> thanks a lot +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + + +### **Shai Almog** — July 2, 2016 at 4:29 am ([permalink](https://www.codenameone.com/blog/in-a-pinch.html#comment-22959)) + +> Shai Almog says: +> +> If I understand correctly you want to do something similar to the phone picture gallery where you swipe between the photos you took. +> +> If you look at that native OS UI you will notice space above or on the sides to keep the aspect ratio of the image in place as you swipe. If you are speaking of a different UI/UX I’ll need a reference. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-a-pinch.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/in-app-purchase-non-renewable-subscriptions.md b/docs/website/content/blog/in-app-purchase-non-renewable-subscriptions.md new file mode 100644 index 0000000000..a4683ffc71 --- /dev/null +++ b/docs/website/content/blog/in-app-purchase-non-renewable-subscriptions.md @@ -0,0 +1,448 @@ +--- +title: Implementing Non-Renewable Subscriptions with In-App Purchase +slug: in-app-purchase-non-renewable-subscriptions +url: /blog/in-app-purchase-non-renewable-subscriptions/ +original_url: https://www.codenameone.com/blog/in-app-purchase-non-renewable-subscriptions.html +aliases: +- /blog/in-app-purchase-non-renewable-subscriptions.html +date: '2016-12-19' +author: Steve Hannah +--- + +![Header Image](/blog/in-app-purchase-non-renewable-subscriptions/in-app-purchase.jpg) + +__ | This is the second post in a three-part series on In-App purchase. Please check out [Part I: Introduction to In-App Purchase](https://www.codenameone.com/blog/intro-to-in-app-purchase.html) and [Part 3: Auto-renewing Subscriptions in iOS and Android](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html). +---|--- + +In [my last post](https://www.codenameone.com/blog/intro-to-in-app-purchase.html) we looked at one-off in-app purchases. In this post we’ll look at subscriptions. As we discussed before, there are two types of subscriptions: + + 1. Non-renewable + + 2. Auto-renewable + +Non-renewable subscriptions are really the same as consumable products, except that they are shareable across all of a user’s devices. Auto-renewable subscriptions, on the other hand, will continue as long as the user doesn’t cancel it. They will be re-billed automatically by the appropriate app-store when the chosen period expires, and all management of the subscription is handled by the the app-store itself. + +__ | The concept of an “Non-renewable” subscription is an invention of the iTunes store. There is no formal equivalent in Google play. In order to create a non-renewable subscription SKU that behaves the same in your iOS and Android apps you would create it as a regular product in Google play, and a Non-renewable subscription in the iTunes store. We’ll learn more about that in a later post when we go into the specifics of app store setup. +---|--- + +## The Server-Side + +Since a subscription purchased on one user device **needs** to be available across all of the user’s devices (Apple’s rules for non-renewable subscriptions), our app will need to have a server-component. In this post, we’ll gloss over that requirement and just “mock” the server interface. We’ll go into the specifics of the server-side in a later post. + +### The Receipts API + +Subscriptions, in Codename One are handled using a new “Receipts” API. It is up to you to register a receipt store with the In-App purchase instance, which allows Codename one to load receipts (presumably from your server), and submit new receipts (presumably to your server). A `Receipt` includes information such as: + + 1. Store code (since you may be dealing with receipts from multiple stores) + + 2. SKU + + 3. Transaction ID (store specific) + + 4. Expiry Date + + 5. Cancellation date + + 6. Purchase date + + 7. Order Data (can be used on the server-side to verify the receipt and load additional receipt details directly from the store it originated from). + +The `Purchase` provides a set of methods for interacting with the receipt store, such as: + + 1. `isSubscribed([skus])` – Checks to see if the user is currently subscribed to any of the provided skus. + + 2. `getExpiryDate([skus])` – Checks the expiry date for a set of skus. + + 3. `synchronizeReceipts()` – Synchronizes the receipts with the receipt store. This will attempt to submit any pending purchase receipts to the receipt store, and the reload receipts from the receipt store. + +In order for any of this to work, you must implement the `ReceiptStore` interface, and register it with the Purchase instance. Your receipt store must implement two methods: + + 1. `fetchReceipts(SuccessCallback callback)` – Loads all of the receipts from your receipt store for the current user. + + 2. `submitReceipt(Receipt receipt, SuccessCallback callback)` – Submits a receipt to your receipt store. This gives you an opportunity to add additional details to the receipt such as an expiry date. + +## The “Hello World” of Non-Renewable Subscriptions + +We’ll expand on the theme of “Buying” the world for this app, except, this time we will just “Rent” the world for a period of time. We’ll have two products: + + 1. A 1 month subscription + + 2. A 1 year subscription + + + + public static final String SKU_WORLD_1_MONTH = "com.codename1.world.subscribe.1month"; + public static final String SKU_WORLD_1_YEAR = "com.codename1.world.subscribe.1year"; + + public static final String[] PRODUCTS = { + SKU_WORLD_1_MONTH, + SKU_WORLD_1_YEAR + }; + +Notice that we create two separate SKUs for the 1 month and 1 year subscription. **Each subscription period must have its own SKU**. I have created an array (`PRODUCTS`) that contains both of the SKUs. This is handy, as you’ll see in the examples ahead, because all of the APIs for checking status and expiry date of a subscription take all of the SKUs in a “subscription group” as input. This is + +__ | Multiple SKUs that sell the same service/product but for different periods form a “subscription group”. Conceptually, customers are not subscribing to a particular SKU, they are subscribing to the subscription group of which that SKU is a member. As an example, if a user purchases a 1 month subscription to “the world”, they are actually just subscribing to “the world” subscription group. +---|--- + +It is up to you to know how your SKUs are grouped together, and any methods in the `Purchase` class that check subscription status or expiry date of a SKU should be passed **all** SKUs of that subscription group. E.g. If you want to know if the user is subscribed to the `SKU_WORLD_1_MONTH` subscription, it would not be sufficient to call `iap.isSubscribed(SKU_WORLD_1_MONTH)`, because that wouldn’t take into account if the user had purchased a 1 year subscription. The correct way is to always call `iap.isSubscribed(SKU_WORLD_1_MONTH, SKU_WORLD_1_YEAR)`, or simply `iap.isSubscribed(PRODUCTS)` since I have placed both SKUs into my PRODUCTS array. + +### Implementing the Receipt Store + +__ | The receipt store is intended to interface with a server so that the subscriptions can be synced with multiple devices, as required by Apple’s guidelines. For this post we’ll just store our receipts on device using internal storage. Moving the logic to a server is a simple matter that we will cover in a future post when we cover the server-side. +---|--- + +![The Receipt store is a layer between your server and Codename One](/blog/in-app-purchase-non-renewable-subscriptions/in-app-purchase-receipt-store-diagram.png) + +A basic receipt store needs to implement just two methods: + + 1. `fetchReceipts` + + 2. `submitReceipt` + +Generally we’ll register it in our app’s init() method so that it is always available. + + + public void init(Object context) { + ... + + Purchase.getInAppPurchase().setReceiptStore(new ReceiptStore() { + + @Override + public void fetchReceipts(SuccessCallback callback) { + // Fetch receipts from storage and pass them to the callback + } + + @Override + public void submitReceipt(Receipt receipt, SuccessCallback callback) { + // Save a receipt to storage. Make sure to call callback when done. + } + }); + } + +These methods are designed to be called asynchronously since real-world apps will always be connecting to some sort of network service. Therefore, instead of returning a value, both of these methods are passed instances of the `SuccessCallback` class. It is important to make sure to call `callback.onSuccess()` **ALWAYS** when the methods have completed, even if there is an error, or the Purchase class will just assume that you’re taking a long time to complete the task, and will continue to wait for you to finish. + +Once implemented, our `fetchReceipts()` method will look like: + + + // static declarations used by receipt store + + // Storage key where list of receipts are stored + private static final String RECEIPTS_KEY = "RECEIPTS.dat"; + + @Override + public void fetchReceipts(SuccessCallback callback) { + Storage s = Storage.getInstance(); + Receipt[] found; + synchronized(RECEIPTS_KEY) { + if (s.exists(RECEIPTS_KEY)) { + List receipts = (List)s.readObject(RECEIPTS_KEY); + found = receipts.toArray(new Receipt[receipts.size()]); + } else { + found = new Receipt[0]; + } + } + // Make sure this is outside the synchronized block + callback.onSucess(found); + } + +This is fairly straight forward. We’re checking to see if we already have a list of receipts stored. If so we return that list to the callback. If not we return an empty array of receipts. + +__ | `Receipt` implements `Externalizable` so you are able to write instances directly to Storage. +---|--- + +The `submitReceipt()` method is a little more complex, as it needs to calculate the new expiry date for our subscription. + + + @Override + public void submitReceipt(Receipt receipt, SuccessCallback callback) { + Storage s = Storage.getInstance(); + synchronized(RECEIPTS_KEY) { + List receipts; + if (s.exists(RECEIPTS_KEY)) { + receipts = (List)s.readObject(RECEIPTS_KEY); + } else { + receipts = new ArrayList(); + } + // Check to see if this receipt already exists + // This probably won't ever happen (that we'll be asked to submit an + // existing receipt, but better safe than sorry + for (Receipt r : receipts) { + if (r.getStoreCode().equals(receipt.getStoreCode()) && + r.getTransactionId().equals(receipt.getTransactionId())) { + // If we've already got this receipt, we'll just this submission. + return; + } + } + + // Now try to find the current expiry date + Date currExpiry = new Date(); + List lProducts = Arrays.asList(PRODUCTS); + for (Receipt r : receipts) { + if (!lProducts.contains(receipt.getSku())) { + continue; + } + if (r.getCancellationDate() != null) { + continue; + } + if (r.getExpiryDate() == null) { + continue; + } + if (r.getExpiryDate().getTime() > currExpiry.getTime()) { + currExpiry = r.getExpiryDate(); + } + } + + // Now set the appropriate expiry date by adding time onto + // the end of the current expiry date + Calendar cal = Calendar.getInstance(); + cal.setTime(currExpiry); + switch (receipt.getSku()) { + case SKU_WORLD_1_MONTH: + cal.add(Calendar.MONTH, 1); + break; + case SKU_WORLD_1_YEAR: + cal.add(Calendar.YEAR, 1); + } + Date newExpiry = cal.getTime(); + + receipt.setExpiryDate(newExpiry); + receipts.add(receipt); + s.writeObject(RECEIPTS_KEY, receipts); + + } + // Make sure this is outside the synchronized block + callback.onSucess(Boolean.TRUE); + } + +The main logic of this method involves iterating through all of the existing receipts to find the **latest** current expiry date, so that when the user purchases a subscription, it is added onto the end of the current subscription (if one exists) rather than going from today’s date. This enables users to safely renew their subscription before the subscription has expired. + +In the real-world, we would implement this logic on the server-side. + +__ | The iTunes store and Play store have no knowledge of your subscription durations. This is why it is up to you to set the expiry date in the `submitReceipt` method. Non-renewable subscriptions are essentially no different than regular consumable products. It is up to you to manage the subscription logic – and Apple, in particular, requires you to do so using a server. +---|--- + +### Synchronizing Receipts + +In order for your app to provide you with current data about the user’s subscriptions and expiry dates, you need to synchronize the receipts with your receipt store. `Purchase` provides a set of methods for doing this. Generally I’ll call one of them inside the `start()` method, and I may resynchronize at other strategic times if I suspect that the information may have changed. + +The following methods can be used for synchronization: + + 1. `synchronizeReceipts()` – Asynchronously synchronizes receipts in the background. You won’t be notified when it is complete. + + 2. `synchronizeReceiptsSync()` – Synchronously synchronizes receipts, and blocks until it is complete. This is safe to use on the EDT as it employs `invokeAndBlock` under the covers. + + 3. `synchronizeReceipts(final long ifOlderThanMs, final SuccessCallback callback)` – Asynchronously synchronizes receipts, but only if they haven’t been synchronized in the specified time period. E.g. In your start() method you might decide that you only want to synchronize receipts once per day. This also includes a callback that will be called when synchronization is complete. + + 4. `synchronizeReceiptsSync(long ifOlderThanMs)` – A synchronous version that will only refetch if data is older than given time. + +In our hello world app we synchronize the subscriptions in a few places. + +At the end of the `start()` method: + + + public void start() { + + ... + + // Now synchronize the receipts + iap.synchronizeReceipts(0, res->{ + // Update the UI as necessary to reflect + + }); + } + +And I also provide a button to allow the user to manually synchronize the receipts. + + + Button syncReceipts = new Button("Synchronize Receipts"); + + syncReceipts.addActionListener(e->{ + + iap.synchronizeReceipts(0, res->{ + // Update the UI + }); + }); + +### Expiry Dates and Subscription Status + +Now that we have a receipt store registered, and we have synchronized our receipts, we can query the `Purchase` instance to see if a SKU or set of SKUs is currently subscribed. There are three useful methods in this realm: + + 1. `boolean isSubscribed(String…​ skus)` – Checks to see if the user is currently subscribed to any of the provided SKUs. + + 2. `Date getExpiryDate(String…​ skus)` – Gets the latest expiry date of a set of SKUs. + + 3. `Receipt getFirstReceiptExpiringAfter(Date dt, String…​ skus)` – This method will return the earliest receipt with an expiry date after the given date. This is needed in cases where you need to decide if the user should have access to some content based on its publication date. E.g. If you published an issue of your e-zine on March 1, and the user purchased a subscription on March 15th, then they should get access to the March 1st issue even though it doesn’t necessarily fall in the subscription period. Being able to easily fetch the first receipt after a given date makes it easier to determine if a particular issue should be covered by a subscription. + +If you need to know more information about subscriptions, you can always just call `getReceipts()` to obtain a list of all of the current receipts and determine for yourself what the user should have access to. + +In the hello world app we’ll use this information in a few different places. On our main form we’ll include a label to show the current expiry date, and we allow the user to press a button to synchronize receipts manually if they think the value is out of date. + + + // ... + + SpanLabel rentalStatus = new SpanLabel("Loading rental details..."); + Button syncReceipts = new Button("Synchronize Receipts"); + + syncReceipts.addActionListener(e->{ + + iap.synchronizeReceipts(0, res->{ + if (iap.isSubscribed(PRODUCTS)) { + rentalStatus.setText("World rental expires "+iap.getExpiryDate(PRODUCTS)); + } else { + rentalStatus.setText("You don't currently have a subscription to the world"); + } + hi.revalidate(); + }); + }); + +### Allowing the User to Purchase the Subscription + +You should now have all of the background required to implement the Hello World Subscription app. So we’ll return to the code and see how the user purchases a subscription. + +In the main form, I want two buttons to subscribe to the “World”, for one month and one year respectively. They look like: + + + Purchase iap = Purchase.getInAppPurchase(); + // ... + Button rentWorld1M = new Button("Rent World 1 Month"); + rentWorld1M.addActionListener(e->{ + String msg = null; + if (iap.isSubscribed(PRODUCTS)) { __**(1)** + msg = "You are already renting the world until " + +iap.getExpiryDate(PRODUCTS) __**(2)** + +". Extend it for one more month?"; + } else { + msg = "Rent the world for 1 month?"; + } + if (Dialog.show("Confirm", msg, "Yes", "No")) { + Purchase.getInAppPurchase().purchase(SKU_WORLD_1_MONTH); __**(3)** + } + }); + + Button rentWorld1Y = new Button("Rent World 1 Year"); + rentWorld1Y.addActionListener(e->{ + String msg = null; + if (iap.isSubscribed(PRODUCTS)) { + msg = "You are already renting the world until "+ + iap.getExpiryDate(PRODUCTS)+ + ". Extend it for one more year?"; + } else { + msg = "Rent the world for 1 year?"; + } + if (Dialog.show("Confirm", msg, "Yes", "No")) { + Purchase.getInAppPurchase().purchase(SKU_WORLD_1_YEAR); + } + }); + +__**1** | In the event handler we check if the user is subscribed by calling `isSubscribed(PRODUCTS)`. Notice that we check it against the array of both the one month and one year subscription SKUs. +---|--- +__**2** | We are able to tell the user when the current expiry date is so that they can gauge whether to proceed. +__**3** | Since this is a non-renewable subscription, we use the `Purchase.purchase()` method. See following note about `subscribe()` vs `purchase()` + +#### subscribe() vs purchase() + +The `Purchase` class includes two methods for initiating a purchase: + + 1. `purchase(sku)` + + 2. `subscribe(sku)` + +Which one you use depends on the type of product that is being purchased. If your product is set up as a subscription in the Google Play store, then you should use `subscribe(sku)`. Otherwise, you should use `purchase(sku)`. + +### Handling Purchase Callbacks + +The purchase callbacks are very similar to the ones that we implemented in the regular in-app purchase examples: + + + @Override + public void itemPurchased(String sku) { + Purchase iap = Purchase.getInAppPurchase(); + + // Force us to reload the receipts from the store. + iap.synchronizeReceiptsSync(0); + ToastBar.showMessage("Your subscription has been extended to "+iap.getExpiryDate(PRODUCTS), FontImage.MATERIAL_THUMB_UP); + } + + @Override + public void itemPurchaseError(String sku, String errorMessage) { + ToastBar.showErrorMessage("Failure occurred: "+errorMessage); + } + +Notice that, in `itemPurchased()` we don’t need to explicitly create any receipts or submit anything to the receipt store. This is handled for you automatically. We do make a call to `synchronizeReceiptsSync()` but this is just to ensure that our toast message has the new expiry date loaded already. + +## Full Source + +[View the full source listing of this application](https://gist.github.com/shannah/f998545f0b17f0c412af54ea2db61e35) + +## Screenshots + +![Main form](/blog/in-app-purchase-non-renewable-subscriptions/in-app-purchase-subscription-main-form.png) + +![Dialog shown when subscribing to a product](/blog/in-app-purchase-non-renewable-subscriptions/in-app-purchase-subscription-dialog.png) + +![Simulator confirm dialog when purchasing a subscription](/blog/in-app-purchase-non-renewable-subscriptions/in-app-purchase-subscription-confirm.png) + +![Upon successful purchase](/blog/in-app-purchase-non-renewable-subscriptions/in-app-purchase-subscription-toastbar-success.png) + +## Summary + +This post demonstrated how to set up an app to use non-renewable subscriptions using in-app purchase. Non-renewable subscriptions are the same as regular consumable products except for the fact that they are shared by all of the user’s devices, and thus, require a server component. The app store has no knowledge of the duration of your non-renewable subscriptions. It is up to you to specify the expiry date of purchased subscriptions on their receipts when they are submitted. Google play doesn’t formally have a “non-renewable” subscription product type. To implement them in Google play, you would just set up a regular product. It is how you handle it internally that makes it a subscription, and not just a regular product. + +Codename One uses the `Receipt` class as the foundation for its subscriptions infrastructure. You, as the developer, are responsible for implementing the `ReceiptStore` interface to provide the receipts. The `Purchase` instance will load receipts from your ReceiptStore, and use them to determine whether the user is currently subscribed to a subscription, and when the subscription expires. + +## Up Next: Auto-Renewable Subscriptions + +The [next post](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html) in this series covers [Auto-renewable subscriptions](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html). +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Giri Sugu** — December 7, 2017 at 6:37 am ([permalink](https://www.codenameone.com/blog/in-app-purchase-non-renewable-subscriptions.html#comment-23763)) + +> Hi. In non-renewable subscriptions i have a couple of questions, +> 1\. if i have 200 products means, do i want to add that all 200 products in iTunes connect +> [2.is]() it possible to set the price and expiry date which i want.(bcoz if i am adding 200 products on iTunes connect i have to set the price.But in that we can able to choose the tier they mentioned.)So is it possible to set the prices +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-app-purchase-non-renewable-subscriptions.html) + + +### **Shai Almog** — December 8, 2017 at 6:51 am ([permalink](https://www.codenameone.com/blog/in-app-purchase-non-renewable-subscriptions.html#comment-23672)) + +> Hi, +> 1\. Yes. +> 2\. I think there is an ability to pick a price but that makes it hard with international sales and coin fluctuations so tiers might be better overall. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-app-purchase-non-renewable-subscriptions.html) + + +### **Julien Sosin** — February 9, 2018 at 7:21 am ([permalink](https://www.codenameone.com/blog/in-app-purchase-non-renewable-subscriptions.html#comment-23896)) + +> Hello. An user cancel his purchase but Apple didn’t send the cancellation_date when I refresh the receipts and I can’t know that the user had cancel his purchase. What can I do ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-app-purchase-non-renewable-subscriptions.html) + + +### **Shai Almog** — February 10, 2018 at 6:01 am ([permalink](https://www.codenameone.com/blog/in-app-purchase-non-renewable-subscriptions.html#comment-23878)) + +> Hi, +> Not much. If Apple doesn’t send the cancellation it’s a problem. Generally with in-app-purchase you should only sell stuff you don’t mind losing occasionally on. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-app-purchase-non-renewable-subscriptions.html) + + +### **Julien Sosin** — February 10, 2018 at 8:57 am ([permalink](https://www.codenameone.com/blog/in-app-purchase-non-renewable-subscriptions.html#comment-23750)) + +> Hi Almog. I guess I should check manually :/ +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-app-purchase-non-renewable-subscriptions.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/in-the-shadow.md b/docs/website/content/blog/in-the-shadow.md new file mode 100644 index 0000000000..5bd1fa20ad --- /dev/null +++ b/docs/website/content/blog/in-the-shadow.md @@ -0,0 +1,144 @@ +--- +title: In the Shadow +slug: in-the-shadow +url: /blog/in-the-shadow/ +original_url: https://www.codenameone.com/blog/in-the-shadow.html +aliases: +- /blog/in-the-shadow.html +date: '2016-08-28' +author: Shai Almog +--- + +![Header Image](/blog/in-the-shadow/dropshadow.png) + +[Diamond](https://twitter.com/diamondobama) asked us about an easy way to do dropshadows in Codename One to which I answered that it’s pretty easy thanks to our [Gaussian blur support](/blog/toastbar-gaussian-blur.html)…​ + +We ended up with this code which is usable but probably not as intuitive for most: + + + Form hi = new Form("Drop Shadow", new BorderLayout(BorderLayout.CENTER_BEHAVIOR_CENTER)); + + FontImage mm = FontImage.createMaterial(FontImage.MATERIAL_PERSON, "Button", 30); + int[] rgb = mm.toImage().getRGB(); + for(int iter = 0 ; iter < rgb.length ; iter++) { + rgb[iter] = rgb[iter] & 0xff000000; + } + Image shadow = Image.createImage(rgb, mm.getWidth(), mm.getHeight()); + if(Display.getInstance().isGaussianBlurSupported()) { + shadow = Display.getInstance().gaussianBlurImage(shadow, 10); + } + + Label top = new Label(mm, "Container"); + Label bottom = new Label(shadow, "Container"); + bottom.getAllStyles().setMargin(1, 0, 1, 0); + bottom.getAllStyles().setMarginUnit(Style.UNIT_TYPE_DIPS); + hi.add(BorderLayout.CENTER, LayeredLayout.encloseIn(bottom, top)); + + hi.show(); + +The effect is attractive and commonplace so I think it would be great to add it universally so we added two methods which will be a part of the coming update. These methods are in the `Effects` class and are both simple utility methods. Once creates a shadow and incorporates it into a new image at the given location. The other returns the shadow alone which you can shift/position as you see fit (e.g. if you have similarly shaped images this might also be useful in terms of CPU/RAM). + + + /** + * Generates a shadow for the source image and returns a new larger image containing the shadow + * + * @param source the source image for whom the shadow should be generated + * @param blurRadius a shadow is blurred using a gaussian blur when available, a value of 10 is often satisfactory + * @param opacity the opacity of the shadow between 0 - 1 where 1 is completely opaque + * @param xDistance the distance on the x axis from the main image body in pixels e.g. a negative value will represent a lightsource from the right (shadow on the left) + * @param yDistance the distance on the y axis from the main image body in pixels e.g. a negative value will represent a lightsource from the bottom (shadow on top) + * @return a new image whose size incorporates x/yDistance + */ + public static Image dropshadow(Image source, int blurRadius, float opacity, int xDistance, int yDistance); + + /** + * Generates a shadow for the source image and returns either the shadow itself or the image merged with the + * shadow. + * + * @param source the source image for whom the shadow should be generated + * @param blurRadius a shadow is blurred using a gaussian blur when available, a value of 10 is often satisfactory + * @param opacity the opacity of the shadow between 0 - 1 where 1 is completely opaque + * @return an image containing the shadow for source + */ + public static Image dropshadow(Image source, int blurRadius, float opacity); + +This can result in simple code to do a drop shadow effect: + + + Form hi = new Form("Drop Shadow", new BorderLayout(BorderLayout.CENTER_BEHAVIOR_CENTER)); + + int twoMM = Display.getInstance().convertToPixels(2); + Image img = duke.scaledWidth(Display.getInstance().getDisplayWidth() / 2); + hi.add(BorderLayout.CENTER, new Label(Effects.dropshadow(img, 10, 0.8f, twoMM, twoMM), "Container")); + + hi.show(); + +__ | The variable duke is the image of the icon placed into the src directory +---|--- +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **beck** — September 11, 2016 at 9:46 am ([permalink](https://www.codenameone.com/blog/in-the-shadow.html#comment-22916)) + +> beck says: +> +> We can use the shadow effect in img only or in the components as well. eg I have a blue background container. Can i have the shadow effect in this container as well? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-the-shadow.html) + + +### **Shai Almog** — September 12, 2016 at 4:17 am ([permalink](https://www.codenameone.com/blog/in-the-shadow.html#comment-22972)) + +> Shai Almog says: +> +> If the background of the container is fixed you can draw the image with the background then create a shadow for that and place everything in a layered layout. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-the-shadow.html) + + +### **Bayu Sanjaya** — September 12, 2016 at 1:09 pm ([permalink](https://www.codenameone.com/blog/in-the-shadow.html#comment-23022)) + +> Bayu Sanjaya says: +> +> can you give us an example for shadowed container? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-the-shadow.html) + + +### **Shai Almog** — September 13, 2016 at 3:47 am ([permalink](https://www.codenameone.com/blog/in-the-shadow.html#comment-21463)) + +> Shai Almog says: +> +> Containers are transparent by default so doing this generically isn’t necessarily ideal. It might also pose a problem if the container is scrollable or if it reflows (e.g. on rotation). I would suggest doing this for individual components within the container. Just paint the component on an image and use that as the shadow base then do something like LayeredLayout.encloseIn(new Label(myShadow), myComponent) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-the-shadow.html) + + +### **Ali Ahmadur Rahman** — August 5, 2018 at 8:42 pm ([permalink](https://www.codenameone.com/blog/in-the-shadow.html#comment-23820)) + +> Ali Ahmadur Rahman says: +> +> Nice tutorial. Hope to get more from you. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-the-shadow.html) + + +### **Martin Brook** — October 28, 2018 at 10:17 am ([permalink](https://www.codenameone.com/blog/in-the-shadow.html#comment-23950)) + +> Martin Brook says: +> +> Great article. thanks a lot for sharing with us. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fin-the-shadow.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/increase-your-build-quotas.md b/docs/website/content/blog/increase-your-build-quotas.md new file mode 100644 index 0000000000..7ddd22bf09 --- /dev/null +++ b/docs/website/content/blog/increase-your-build-quotas.md @@ -0,0 +1,112 @@ +--- +title: Increase your Build Quotas +slug: increase-your-build-quotas +url: /blog/increase-your-build-quotas/ +original_url: https://www.codenameone.com/blog/increase-your-build-quotas.html +aliases: +- /blog/increase-your-build-quotas.html +date: '2018-07-24' +author: Shai Almog +--- + +![Header Image](/blog/increase-your-build-quotas/generic-java-2.jpg) + +The most common question we get about Codename One is: “Is Codename One Free”. The direct answer is “Yes” but we don’t want to mislead. You can work with the open source code, which is just as free as any other project. But it’s not for the faint of heart…​ +The build servers have quotas so we won’t go out of business. This is perceived by developers as “not free” but since no one else offers build servers I have an issue with that perception. To battle that perception we’re increasing the build quotas. + +Sort of…​ + +To keep us sustainable paying users essentially pay for the free users. Worse, it’s only the pro/enterprise accounts that cover these costs. + +So in order to increase the quotas we need your help. We’ll give you increased quotas for friends of yours that join e.g. you bring your friends and we’ll increase your build quotas respectively. + +For every friend we’ll add 512kb to your jar size limit and 50 build credits. This is a permanent addition that will come into effect during the quota reset (it isn’t immediate). We’ll also count that friend as if he referred one person already so he’ll have more than the default count! +Currently this is capped off at 15 friends which should give you plenty of room to grow. +These benefits are perpetual and aren’t dependent on your friends staying or paying. However, we reserve the right to revoke these credits for abuse of this system! + +Here’s the kicker, we just updated all the users in the database currently to 1 referral by default. So all active Codename One users should already have a larger build credit by default. Due to technical reasons we can’t do it to old users that didn’t use Codename One since our migration from App Engine…​ + +### How Does it Work? + +You can invite friends by sharing a special URL which you can see in your console [here](https://www.codenameone.com/build-server.html) under the Account tab. E.g. mine is: ``. + +__ | You might need to logout and login again to see this entry. It should be below the token +---|--- + +The important aspect here is the `?ref=baa9d923-b26a-430b-a814-02cf55605231` part. You can attach it to any html URL in this site including this page e.g.: `` would be valid. + +However `` isn’t valid as it doesn’t contain an html file in the URL. + +### Terms and Questions + +#### Does this Apply to Paid Users? + +Yes. If you ever cancel your account you’d revert to paid mode and still have your increased credits. If you signup for a paid program and downgrade you won’t lose any signups during the paid duration or after. + +#### How does this Work? + +The referral URL sets a cookie in the users browser that is active for 6 months. If during those 6 months the user signs up he is counted. +You would need to promote Codename One to your friends/social network to get the additional credits. + +#### What if a User Clicks two URL’s? + +The last one is counted. This is the industry standard. + +#### How can I Monitor This? + +Right now you will only know when the build credits are reset. However, we plan to introduce a UI that will let you see how many users you referred. + +#### How do you Check for Abuse? + +We only count activated users. We check user behavioral patterns through an automated system that alerts us of potential abuse. + +### Future Directions + +We’d like to extend this to push notification as well. We have some ideas on how to provide push support for free/basic accounts but for that we would probably want to redesign our push servers. + +That’s a bit of an undertaking and we’ll only start that off if this program proves successful. + +I hope you all take advantage of this as much as possible! + +A Word About the 1MB Jar Size + +We’re doing this mostly to battle a perception issue. The JAR size limit should be enough for relatively demanding apps. It’s generally a good practice to stay within it. + +The JAR size limit refers to the size of the JAR sent to the server. Not the one returned. + +Native libs are essentially free since they are fetched from gradle/cocoapods. By default a clean hello world app is around 2-3kb and the Uber/Facebook clones fall well below the 1mb limit. + +It’s a good limit to abide by. It means your builds will be faster and the end result application will be smaller. You shouldn’t need a larger app size. + +Keep in mind that a 1mb jar app can grow up to 16 times on iOS and a bit less on Android. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Synapsido** — August 21, 2018 at 12:22 am ([permalink](https://www.codenameone.com/blog/increase-your-build-quotas.html#comment-24006)) + +> Synapsido says: +> +> I’m free user for now, I have several developer fiends invited, where can I see my total Quotas in my account…? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fincrease-your-build-quotas.html) + + +### **Shai Almog** — August 21, 2018 at 8:23 am ([permalink](https://www.codenameone.com/blog/increase-your-build-quotas.html#comment-21538)) + +> Shai Almog says: +> +> On the first of the month when your credits are reset you can see how many clicked and created an account based on the build credits you would have. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fincrease-your-build-quotas.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/inspect-component.md b/docs/website/content/blog/inspect-component.md new file mode 100644 index 0000000000..0a334d65b5 --- /dev/null +++ b/docs/website/content/blog/inspect-component.md @@ -0,0 +1,91 @@ +--- +title: 'New Feature: Inspect Component' +slug: inspect-component +url: /blog/inspect-component/ +original_url: https://www.codenameone.com/blog/inspect-component.html +aliases: +- /blog/inspect-component.html +date: '2022-03-28' +author: Steve Hannah +description: We’ve added support for "Inspect Component", which is similar to the + "Inspect Element" feature available in Chrome. +--- + +We’ve added support for "Inspect Component", which is similar to the "Inspect Element" feature available in Chrome. + +![Inspect Component - Codename One](/blog/inspect-component/Inspect-Component-Codename-One-1024x536.jpg) + +Continuing in the direction of improving the development experience inside the Codename One simulator, we have made another batch of small improvements this week. Notably, we’ve added support for “Inspect Component”, which is similar to the “Inspect Element” feature available in Chrome. Now, if you right-click on a component in the simulator, it will provide you with a context menu. + +![](/blog/inspect-component/inspect-component.png) + +Figure 1. The "Inspect Component" option in the context menu. + +If you select the “Inspect Component” option in this menu, it will select the selected component in the “Components” panel, and in the “Component details”. + +The “Component Inspector” has been available as part of the simulator for a long time, but selecting a particular component used to require you to expand the component tree nodes manually until you found the component you were looking for. + +The simulator would help you a little bit by placing a translucent red highlight over the currently selected node’s corresponding component, but it could still be a little bit tedious to have to manually walk through the tree to find the component you wanted. + +![](/blog/inspect-component/selected-component.png) + +Figure 2. After choosing "Inspect Component", the "Components" panel auto-expands and selects the corresponding node, and the "Component details" panel is populated with the selected component details. + +You’ll notice also, that the “Component Details” will automatically populate with the details of your selected component. Most for the fields in the component details form are read only, but the **UIID** field can be edited, allowing you to experiment with different styles for your elements directly in the simulator. + +### Disabling the Context Menu + +If your application needs to handle “Right Mouse-click” events, then the context menu may interfere with your app. In such cases you can disable the context menu by toggling the ![arrow button](/blog/inspect-component/arrow-button.png) button found on the toolbar of the **Components** panel. Once toggled off, the button icon will change to ![arrow button disabled](/blog/inspect-component/arrow-button-disabled.png). + +![](/blog/inspect-component/components-toolbar.png) + +Figure 3. The "Components" panel toolbar, which includes a toggle button to enable/disable the context menu. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved here for historical context. New discussion happens in the Discussion section below._ + + +### **plumberg** — March 29, 2022 at 5:28 pm ([permalink](https://www.codenameone.com/blog/inspect-component.html#comment-24528)) + +> plumberg says: +> +> Tested it out for a bit yesterday. Looks great and very convenient! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finspect-component.html) + + +### **ThomasH99** — April 5, 2022 at 11:21 am ([permalink](https://www.codenameone.com/blog/inspect-component.html#comment-24530)) + +> ThomasH99 says: +> +> It is really great with these improvements! While you’re at it, Steve, improving the testing (test automation) would also make a huge difference. The old support is promising but misses some small things to be really useful. Let me know if this migth make it to your todo list and I’d be happy to provide input and feedback 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finspect-component.html) + + +### **Steve Hannah** — April 5, 2022 at 11:15 pm ([permalink](https://www.codenameone.com/blog/inspect-component.html#comment-24531)) + +> Steve Hannah says: +> +> We are making a push right now to improve the development experience in the simulator. No promises, filing an RFE in the issue tracker is where to start the ball rolling. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finspect-component.html) + + +### **ThomasH99** — April 10, 2022 at 12:30 pm ([permalink](https://www.codenameone.com/blog/inspect-component.html#comment-24533)) + +> ThomasH99 says: +> +> Great, I hope for the best :-). The TestRecorder has a lot of potential and would make the Simulator UI even more powerful and impressive. I’ve filed an RFE here: +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finspect-component.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/inspecting-components.md b/docs/website/content/blog/inspecting-components.md new file mode 100644 index 0000000000..768762b255 --- /dev/null +++ b/docs/website/content/blog/inspecting-components.md @@ -0,0 +1,92 @@ +--- +title: Inspecting Components +slug: inspecting-components +url: /blog/inspecting-components/ +original_url: https://www.codenameone.com/blog/inspecting-components.html +aliases: +- /blog/inspecting-components.html +date: '2013-02-19' +author: Shai Almog +--- + +![Header Image](/blog/inspecting-components/inspecting-components-1.png) + + + + +[ +![Picture](/blog/inspecting-components/inspecting-components-1.png) +](/img/blog/old_posts/inspecting-components-large-2.png) + +First, let me start with an apology for not blogging as frequently. Its been hectic these past few weeks and I could barely find the time to write this! That’s generally a “good thing(tm)”. + + +One of my favorite things about working with Codename One is the GUI builder, it solves a lot of the headaches of handcoding/positioning elements into place especially when coupled with the Codename One LIVE! application. However, not all of us use the GUI builder and even when we do we sometimes end up writing code manually. + + +In those cases it is sometimes pretty difficult to visualize the UI and how to properly style it in the designer tool e.g. when you run into + +inexplicable spacing that is clearly not your intention. + + + + +For this purpose we now have the component inspector in the simulator tool. It allows us to inspect the component hierarchy in a running simulator, see the classes and UIID’s involved etc. + + +You can reach the component inspector via the simulator menu after which you can just expand the UI to see the elements within and understand more about the way Codename + +One lays out everything. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — February 24, 2013 at 6:51 pm ([permalink](https://www.codenameone.com/blog/inspecting-components.html#comment-21637)) + +> Anonymous says: +> +> This feature sounds like exactly what I need. Where do I find it? I have the plugin version 1.0.33 and no updates available but I can’t find this tool +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finspecting-components.html) + + +### **Anonymous** — February 25, 2013 at 4:53 am ([permalink](https://www.codenameone.com/blog/inspecting-components.html#comment-21728)) + +> Anonymous says: +> +> I was sure it was there already… Updated the version to 34 right now so it has to be there now. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finspecting-components.html) + + +### **Anonymous** — February 27, 2013 at 8:35 am ([permalink](https://www.codenameone.com/blog/inspecting-components.html#comment-21831)) + +> Anonymous says: +> +> Very neat. Refresh doesn’t seem to work. I need to close the inspector dialog and re-open when I change forms to get an updated component tree. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finspecting-components.html) + + +### **Anonymous** — February 27, 2013 at 9:12 am ([permalink](https://www.codenameone.com/blog/inspecting-components.html#comment-24248)) + +> Anonymous says: +> +> Oops. Wrote the code but forgot to wire it. Will be fixed for the next update. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finspecting-components.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/install-home-screen.md b/docs/website/content/blog/install-home-screen.md new file mode 100644 index 0000000000..47cad052f5 --- /dev/null +++ b/docs/website/content/blog/install-home-screen.md @@ -0,0 +1,42 @@ +--- +title: Install on Home Screen +slug: install-home-screen +url: /blog/install-home-screen/ +original_url: https://www.codenameone.com/blog/install-home-screen.html +aliases: +- /blog/install-home-screen.html +date: '2018-12-03' +author: Shai Almog +--- + +![Header Image](/blog/install-home-screen/html5-banner.jpg) + +We talked about our support for [Progressive Web Apps before](/blog/progressive-web-apps.html). We added quite a few enhancements since that support was introduced and it’s a pretty powerful feature. Personally I consider it a killer feature, even if Google decides to [ban your account](https://www.reddit.com/r/androiddev/comments/9mpyyi/google_play_developer_account_terminated_due_to/) you can still distribute your app. + +One of the cool features is the seamlessness. Most of the functionality “just works”. However, there are some cases where we need explicit hints due to the different behavior of desktop/mobile and web. + +One such case is installation. PWA’s support an icon on the device home screen, but you need to explicitly ask the browser to install that icon. That’s unique to PWA’s and requires a new API to support that behavior. That’s why we introduced `onCanInstallOnHomescreen`, `canInstallOnHomescreen()` and `promptInstallOnHomescreen()` to help with that process. You can use them as: + + + onCanInstallOnHomescreen(()->{ + if (canInstallOnHomescreen()) { + if (promptInstallOnHomescreen()) { + // User accepted installation + } else { + // user rejected installation + } + } + }); + +__ | This code expects `import static com.codename1.ui.CN.*;` +---|--- + +The code would prompt the user to install on the home screen in OS’s where this is appropriate. Notice that this will prompt the user once to install on the home screen so you don’t need additional guards against duplicate prompts. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/installing-on-a-windows-phone-device.md b/docs/website/content/blog/installing-on-a-windows-phone-device.md new file mode 100644 index 0000000000..e46e946b7a --- /dev/null +++ b/docs/website/content/blog/installing-on-a-windows-phone-device.md @@ -0,0 +1,50 @@ +--- +title: Installing On A Windows Phone Device +slug: installing-on-a-windows-phone-device +url: /blog/installing-on-a-windows-phone-device/ +original_url: https://www.codenameone.com/blog/installing-on-a-windows-phone-device.html +aliases: +- /blog/installing-on-a-windows-phone-device.html +date: '2012-10-23' +author: Shai Almog +--- + +![Header Image](/blog/installing-on-a-windows-phone-device/codename-one-charts-1.png) + +We recently added Windows Phone support to Codename One, this allows you to build your applications as a Windows XAP application for installation on a Windows Phone device. Unfortunately of all the platforms we support (including J2ME and iOS) MS is the only company that chose not to allow standard OTA distribution so you will literally need a PC in order to install the application with a cable. + +MS has a sort of beta distribution option which might alleviate the problem but we didn’t get a chance to try it out. + +Sending a build for Windows Phone is similar to sending it to any other platform, with the latest distribution just right click and send a build for Windows Phone, its just that simple. + +Unlike most other platforms MS didn’t burden us with the silly need to sign the distribution (they can sign it themselves when we upload to the store, makes MUCH more sense!). + +Installing said build requires that you enable your device for development for which you need to pay Microsoft. The instructions for doing all of this are all +[ +here +](http://msdn.microsoft.com/en-us/library/windowsphone/develop/gg588378%28v=vs.92%29.aspx) +. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — January 22, 2015 at 4:42 pm ([permalink](https://www.codenameone.com/blog/installing-on-a-windows-phone-device.html#comment-21607)) + +> Anonymous says: +> +> When you’re testing your app on the emulator, leave the emulator open between debugging sessions so you can run your app again quickly. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finstalling-on-a-windows-phone-device.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/integrating-3rd-party-native-sdks-part-1.md b/docs/website/content/blog/integrating-3rd-party-native-sdks-part-1.md new file mode 100644 index 0000000000..9ec0646ec6 --- /dev/null +++ b/docs/website/content/blog/integrating-3rd-party-native-sdks-part-1.md @@ -0,0 +1,584 @@ +--- +title: Integrating 3rd Party Native SDKs Part I +slug: integrating-3rd-party-native-sdks-part-1 +url: /blog/integrating-3rd-party-native-sdks-part-1/ +original_url: https://www.codenameone.com/blog/integrating-3rd-party-native-sdks-part-1.html +aliases: +- /blog/integrating-3rd-party-native-sdks-part-1.html +date: '2015-09-28' +author: Steve Hannah +--- + +![Header Image](/blog/integrating-3rd-party-native-sdks-part-1/native-sdks-header.jpg) + +This past Thursday, we held our fourth webinar, and the topic was how to incorporate 3rd party native libraries into a Codename One app. I used the recently released [FreshDesk cn1lib](http://shannah.github.io/cn1-freshdesk/) as a case study for this webinar. As the topic is a little involved, I decided to break it up into two webinars. In [part one](https://codenameone.adobeconnect.com/p8tau90yr1d/), we focused on the public API and architecture involved in developing a wrapper for a native SDK, and walked through the native implementation for Android. + +[View a Recording of the Part I webinar](https://youtu.be/1bNi9IVlQ_g) + +In [part 2](https://www.eventbrite.co.uk/e/enhancing-your-app-with-3rd-party-native-libraries-part-2-tickets-18826645002), scheduled for Thursday October 8th, we’ll show how to implement the iOS side of the library. + +[Sign up for Enhancing your App with 3rd Party Native Libraries Part 2](https://www.eventbrite.co.uk/e/enhancing-your-app-with-3rd-party-native-libraries-part-2-tickets-18826645002) + +## The Companion Tutorial + +For those of you who prefer written tutorials, I will be publishing a parallel 3-part series on this topic in the blog. The first part of the tutorial is contained in the remainder of this blog post. + +The following is a description of the procedure that was used to create the [Codename One FreshDesk library](http://shannah.github.io/cn1-freshdesk/). This process can be easily adapted to wrap any native SDK on Android and iOS. + +## Step 1 : Review the FreshDesk SDKs + +Before we begin, we’ll need to review the Android and iOS SDKs. + + 1. **FreshDesk Android SDK** : [Integration Guide](http://developer.freshdesk.com/mobihelp/android/integration_guide/) | [API Docs](http://developer.freshdesk.com/mobihelp/android/api/reference/com/freshdesk/mobihelp/package-summary.html) + + 2. **FreshDesk iOS SDK** : [Integration Guide](http://developer.freshdesk.com/mobihelp/ios/integration_guide/) | [API Docs](http://developer.freshdesk.com/mobihelp/ios/api/) + +In reviewing the SDKs, I’m looking to answer two questions: + + 1. What should my Codename One FreshDesk API look like? + + 2. What will be involved in integrating the native SDK in my app or lib? + +## Step 2: Designing the Codename One Public API + +When designing the Codename One API, I often begin by looking at the [Javadocs](http://developer.freshdesk.com/mobihelp/android/api/reference/com/freshdesk/mobihelp/package-summary.html) for the native Android SDK. If the class hierarchy doesn’t look too elaborate, I may decide model my Codename One public API fairly closely on the Android API. On the other hand, if I only need a small part of the SDK’s functionality, I may choose to create my abstractions around just the functionality that I need. + +In the case of the FreshDesk SDK, it looks like most of the functionality is handled by one central class `Mobihelp`, with a few other POJO classes for passing data to and from the service. This is a good candidate for a comprehensive Codename One API. + +Before proceeding, we also need to look at the iOS API to see if there are any features that aren’t included. While naming conventions in the iOS API are a little different than those in the Android API, it looks like they are functionally the same. + +Therefore, I choose to create a class hierarchy and API that closely mirrors the Android SDK. + +## Step 3: The Architecture and Internal APIs + +A Codename One library that wraps a native SDK, will generally consist of the following: + + 1. **Public Java API** , consisting of pure Java classes that are intended to be used by the outside world. + + 2. **Native Interface(s)**. The Native Interface(s) act as a conduit for the public Java API to communicate to the native SDK. Parameters in native interface methods are limited to primitive types, arrays of primitive types, and Strings, as are return values. + + 3. **Native code**. Each platform must include an implementation of the Native Interface(s). These implementations are written in the native language of the platform (e.g. Java for Android, and Objective-C for iOS). + + 4. **Native dependencies**. Any 3rd party libraries required for the native code to work, need to be included for each platform. On android, this may mean bundling .jar files, .aar files, or .andlib files. On iOS, this may mean bundling .h files, .a files, and .bundle files. + + 5. **Build hints**. Some libraries will require you to add some extra build hints to your project. E.g. On Android you may need to add permissions to the manifest, or define services in the `` section of the manifest. On iOS, this may mean specifying additional core frameworks for inclusion, or adding build flags for compilation. + +The following diagram shows the dependencies in a native library: + +![fc8a77d2 61e0 11e5 9ecf bf381d4ac966](/blog/integrating-3rd-party-native-sdks-part-1/fc8a77d2-61e0-11e5-9ecf-bf381d4ac966.png) + +In the specific case of our FreshDesk API, the public API and classes will look like: + +![5fe88406 61e4 11e5 951e e09bd28a93c9](/blog/integrating-3rd-party-native-sdks-part-1/5fe88406-61e4-11e5-951e-e09bd28a93c9.png) + +### Things to Notice + + 1. The public API consists of the main class ([`Mobihelp`](https://github.com/shannah/cn1-freshdesk/blob/master/cn1-freshdesk-demo/src/com/codename1/freshdesk/Mobihelp.java)), and a few supporting classes ([`FeedbackRequest`](https://github.com/shannah/cn1-freshdesk/blob/master/cn1-freshdesk-demo/src/com/codename1/freshdesk/FeedbackRequest.java), [`FeedbackType`](https://github.com/shannah/cn1-freshdesk/blob/master/cn1-freshdesk-demo/src/com/codename1/freshdesk/FeedbackType.java), [`MobihelpConfig`](https://github.com/shannah/cn1-freshdesk/blob/master/cn1-freshdesk-demo/src/com/codename1/freshdesk/MobihelpConfig.java), [`MobihelpCallbackStatus`](https://github.com/shannah/cn1-freshdesk/blob/master/cn1-freshdesk-demo/src/com/codename1/freshdesk/MobihelpCallbackStatus.java)), which were copied almost directly from the Android SDK. + + 2. The only way for the public API to communicate with the native SDK is via the [`MobihelpNative`](https://github.com/shannah/cn1-freshdesk/blob/master/cn1-freshdesk-demo/src/com/codename1/freshdesk/MobihelpNative.java) interface. + + 3. We introduced the [`MobihelpNativeCallback`](https://github.com/shannah/cn1-freshdesk/blob/master/cn1-freshdesk-demo/src/com/codename1/freshdesk/MobihelpNativeCallback.java) class to facilitate native code calling back into the public API. This was necessary for a few methods that used asynchronous callbacks. + +## Step 4: Implement the Public API and Native Interface + +We have already looked at the final product of the public API in the previous step, but let’s back up and walk through the process step-by-step. + +I wanted to model my API closely around the Android API, and the central class that includes all of the functionality of the SDK is the [com.freshdesk.mobihelp.Mobihelp class](http://developer.freshdesk.com/mobihelp/android/api/reference/com/freshdesk/mobihelp/Mobihelp.html), so we begin there. + +We’ll start by creating our own package (`com.codename1.freshdesk`) and our own `Mobihelp` class inside it. + +### Adapting Method Signatures + +#### The `Context` parameter + +In a first glance at the [com.freshdesk.mobihelp.Mobihelp API](http://developer.freshdesk.com/mobihelp/android/api/reference/com/freshdesk/mobihelp/Mobihelp.html) we see that many of the methods take a parameter of type [`android.content.Context`](http://developer.android.com/reference/android/content/Context.html). This class is part of the core Android SDK, and will not be accessible to any pure Codename One APIs. Therefore, our public API cannot include any such references. Luckily, we’ll be able to access a suitable context in the native layer, so we’ll just omit this parameter from our public API, and inject them in our native implementation. + +Hence, the method signature `public static final void setUserFullName (Context context, String name)` will simply become `public static final void setUserFullName (String name)` in our public API. + +#### Non-Primitive Parameters + +Although our public API isn’t constrained by the same rules as our Native Interfaces with respect to parameter and return types, we need to be cognizant of the fact that parameters we pass to our public API will ultimately be funnelled through our native interface. Therefore, we should pay attention to any parameters or return types that can’t be passed directly to a native interface, and start forming a strategy for them. E.g. consider the following method signature from the Android `Mobihelp` class: + + + public static final void showSolutions (Context activityContext, ArrayList tags) + +We’ve already decided to just omit the `Context` parameter in our API, so that’s a non-issue. But what about the `ArrayList` tags parameter? Passing this to our public API is no problem, but when we implement the public API, how will we pass this `ArrayList` to our native interface, since native interfaces don’t allow us to arrays of strings as parameters? + +I generally use one of three strategies in such cases: + + 1. Encode the parameter as either a single String (e.g. using JSON or some other easily parseable format) or a byte[] array (in some known format that can easily be parsed in native code). + + 2. Store the parameter on the Codename One side and pass some ID or token that can be used on the native side to retrieve the value. + + 3. If the data structure can be expressed as a finite number of primitive values, then simply design the native interface method to take the individual values as parameters instead of a single object. E.g. If there is a `User` class with properties `name` and `phoneNumber`, the native interface can just have `name` and `phoneNumber parameters rather than a single `user` parameter. + +In this case, because an array of strings is such a simple data structure, I decided to use a variation on strategy number 1: Merge the array into a single string with a delimiter. + +In any case, we don’t have to come up with the specifics right now, as we are still on the public API, but it will pay dividends later if we think this through ahead of time. + +#### Callbacks + +It is quite often the case that native code needs to call back into Codename One code when an event occurs. This may be connected directly to an API method call (e.g. as the result of an asynchronous method invocation), or due to something initiated by the operating system or the native SDK on its own (e.g. a push notification, a location event, etc..). + +Native code will have access to both the Codename One API and any native APIs in your app, but on some platforms, accessing the Codename One API may be a little tricky. E.g. on iOS you’ll be calling from Objective-C back into Java which requires knowledge of Codename One’s java-to-objective C conversion process. In general, I have found that the easiest way to facilitate callbacks is to provide abstractions that involve static java methods (in Codename One space) that accept and return primitive types. + +In the case of our `Mobihelp` class, the following method hints at the need to have a “callback plan”: + + + public static final void getUnreadCountAsync (Context context, UnreadUpdatesCallback callback) + +The interface definition for `UnreadUpdatesCallback` is: + + + public interface UnreadUpdatesCallback { + //This method is called once the unread updates count is available. + void onResult(MobihelpCallbackStatus status, Integer count); + + } + +I.e. If we were to implement this method (which I plan to do), we need to have a way for the native code to call the `callback.onResult()` method of the passed parameter. + +So we have two issues that will need to be solved here: + + 1. How to pass the `callback` object through the native interface. + + 2. How to **call** the `callback.onResult()` method from native code at the right time. + +For the first issue, we’ll use strategy #2 that we mentioned previously: (Store the parameter on the Codename One side and pass some ID or token that can be used on the native side to retrieve the value). + +For the second issue, we’ll create a static method that can take the token generated to solve the first issue, and call the stored `callback` object’s `onResult()` method. We abstract both sides of this process using the [`MobihelpNativeCallback` class](https://github.com/shannah/cn1-freshdesk/blob/master/cn1-freshdesk-demo/src/com/codename1/freshdesk/MobihelpNativeCallback.java). + + + public class MobihelpNativeCallback { + private static int nextId = 0; + private static Map callbacks = new HashMap(); + + static int registerUnreadUpdatesCallback(UnreadUpdatesCallback callback) { + callbacks.put(nextId, callback); + return nextId++; + } + + public static void fireUnreadUpdatesCallback(int callbackId, final int status, final int count) { + final UnreadUpdatesCallback cb = callbacks.get(callbackId); + if (cb != null) { + callbacks.remove(callbackId); + Display.getInstance().callSerially(new Runnable() { + + public void run() { + MobihelpCallbackStatus status2 = MobihelpCallbackStatus.values()[status]; + cb.onResult(status2, count); + } + + }); + } + } + + } + +**Things to notice here:** + + 1. This class uses a static `Map` member to keep track of all callbacks, mapping a unique integer ID to each callback. + + 2. The `registerUnreadUpdatesCallback()` method takes an `UnreadUpdatesCallback` object, places it in the `callbacks` map, and returns the integer **token** that can be used to fire the callback later. This method would be called by the public API inside the `getUnreadCountAsync()` method implementation to convert the `callback` into an integer, which can then be passed to the native API. + + 3. The `fireUnreadUpdatesCallback()` method would be called later from native code. Its first parameter is the token for the callback to call. + + 4. We wrap the `onResult()` call inside a `Display.callSerially()` invocation to ensure that the callback is called on the EDT. This is a general convention that is used throughout Codename One, and you’d be well-advised to follow it. **Event handlers** should be run on the EDT unless there is a good reason not to – and in that case your documentation and naming conventions should make this clear to avoid accidentally stepping into multithreading hell! + +### Initialization + +Most Native SDKs include some sort of initialization method where you pass your developer and application credentials to the API. When I filled in FreshDesk’s web-based form to create a new application, it generated an application ID, an app “secret”, and a “domain”. The SDK requires me to pass all three of these values to its `init()` method via the `MobihelpConfig` class. + +Note, however, that FreshDesk (and most other service provides that have native SDKs) requires me to create different Apps for each platform. This means that my App ID and App secret will be different on iOS than they will be on Android. + +Therefore our public API needs to enable us to provide multiple credentials in the same app, and our API needs to know to use the correct credentials depending on the device that the app is running on. + +There are many solutions to this problem, but the one I chose was to provide two different `init()` methods: + + + public final static void initIOS(MobihelpConfig config) + +and + + + public final static void initAndroid(MobihelpConfig config) + +Then I can set up the API with code like: + + + MobihelpConfig config = new MobihelpConfig(); + config.setAppSecret("xxxxxxx"); + config.setAppId("freshdeskdemo-2-xxxxxx"); + config.setDomain("codenameonetest1.freshdesk.com"); + Mobihelp.initIOS(config); + + config = new MobihelpConfig(); + config.setAppSecret("yyyyyyyy"); + config.setAppId("freshdeskdemo-1-yyyyyyyy"); + config.setDomain("https://codenameonetest1.freshdesk.com"); + Mobihelp.initAndroid(config); + +### The Resulting Public API + + + public class Mobihelp { + + private static char[] separators = new char[]{',','|','/','@','#','%','!','^','&','*','=','+','*','<'}; + private static MobihelpNative peer; + + public static boolean isSupported() { + .... + } + + public static void setPeer(MobihelpNative peer) { + .... + } + + //Attach the given custom data (key-value pair) to the conversations/tickets. + public final static void addCustomData(String key, String value) { + ... + } + //Attach the given custom data (key-value pair) to the conversations/tickets with the ability to flag sensitive data. + public final static void addCustomData(String key, String value, boolean isSensitive) { + ... + } + //Clear all breadcrumb data. + public final static void clearBreadCrumbs() { + ... + } + //Clear all custom data. + public final static void clearCustomData() { + ... + } + //Clears User information. + public final static void clearUserData() { + ... + } + //Retrieve the number of unread items across all the conversations for the user synchronously i.e. + public final static int getUnreadCount() { + ... + } + + //Retrieve the number of unread items across all the conversations for the user asynchronously, count is delivered to the supplied UnreadUpdatesCallback instance Note : This may return 0 or stale value when there is no network connectivity etc + public final static void getUnreadCountAsync(UnreadUpdatesCallback callback) { + ... + } + //Initialize the Mobihelp support section with necessary app configuration. + public final static void initAndroid(MobihelpConfig config) { + ... + } + + public final static void initIOS(MobihelpConfig config) { + ... + } + + + //Attaches the given text as a breadcrumb to the conversations/tickets. + public final static void leaveBreadCrumb(String crumbText) { + ... + } + //Set the email of the user to be reported on the Freshdesk Portal + public final static void setUserEmail(String email) { + ... + } + + //Set the name of the user to be reported on the Freshdesk Portal. + public final static void setUserFullName(String name) { + ... + } + + //Display the App Rating dialog with option to Rate, Leave feedback etc + public static void showAppRateDialog() { + ... + } + //Directly launch Conversation list screen from anywhere within the application + public final static void showConversations() { + ... + } + //Directly launch Feedback Screen from anywhere within the application. + public final static void showFeedback(FeedbackRequest feedbackRequest) { + ... + } + //Directly launch Feedback Screen from anywhere within the application. + public final static void showFeedback() { + ... + } + //Displays the Support landing page (Solution Article List Activity) where only solutions tagged with the given tags are displayed. + public final static void showSolutions(ArrayList tags) { + ... + } + + private static String findUnusedSeparator(ArrayList tags) { + ... + + } + + //Displays the Support landing page (Solution Article List Activity) from where users can do the following + //View solutions, + //Search solutions, + public final static void showSolutions() { + ... + } + //Displays the Integrated Support landing page where only solutions tagged with the given tags are displayed. + public final static void showSupport(ArrayList tags) { + ... + } + + //Displays the Integrated Support landing page (Solution Article List Activity) from where users can do the following + //View solutions, + //Search solutions, + // Start a new conversation, + //View existing conversations update/ unread count etc + public final static void showSupport() { + ... + } + + } + +### The Native Interface + +The final native interface is nearly identical to our public API, except in cases where the public API included non-primitive parameters. + + + public interface MobihelpNative extends NativeInterface { + + /** + * @return the appId + */ + public String config_getAppId(); + + /** + * @param appId the appId to set + */ + public void config_setAppId(String appId); + + /** + * @return the appSecret + */ + public String config_getAppSecret(); + + /** + * @param appSecret the appSecret to set + */ + public void config_setAppSecret(String appSecret); + /** + * @return the domain + */ + public String config_getDomain(); + /** + * @param domain the domain to set + */ + public void config_setDomain(String domain) ; + + /** + * @return the feedbackType + */ + public int config_getFeedbackType() ; + + /** + * @param feedbackType the feedbackType to set + */ + public void config_setFeedbackType(int feedbackType); + + /** + * @return the launchCountForReviewPrompt + */ + public int config_getLaunchCountForReviewPrompt() ; + /** + * @param launchCountForReviewPrompt the launchCountForReviewPrompt to set + */ + public void config_setLaunchCountForReviewPrompt(int launchCountForReviewPrompt); + /** + * @return the prefetchSolutions + */ + public boolean config_isPrefetchSolutions(); + /** + * @param prefetchSolutions the prefetchOptions to set + */ + public void config_setPrefetchSolutions(boolean prefetchSolutions); + /** + * @return the autoReplyEnabled + */ + public boolean config_isAutoReplyEnabled(); + + /** + * @param autoReplyEnabled the autoReplyEnabled to set + */ + public void config_setAutoReplyEnabled(boolean autoReplyEnabled) ; + + /** + * @return the enhancedPrivacyModeEnabled + */ + public boolean config_isEnhancedPrivacyModeEnabled() ; + + /** + * @param enhancedPrivacyModeEnabled the enhancedPrivacyModeEnabled to set + */ + public void config_setEnhancedPrivacyModeEnabled(boolean enhancedPrivacyModeEnabled) ; + + + + //Attach the given custom data (key-value pair) to the conversations/tickets. + public void addCustomData(String key, String value); + //Attach the given custom data (key-value pair) to the conversations/tickets with the ability to flag sensitive data. + public void addCustomDataWithSensitivity(String key, String value, boolean isSensitive); + //Clear all breadcrumb data. + public void clearBreadCrumbs() ; + //Clear all custom data. + public void clearCustomData(); + //Clears User information. + public void clearUserData(); + //Retrieve the number of unread items across all the conversations for the user synchronously i.e. + public int getUnreadCount(); + + //Retrieve the number of unread items across all the conversations for the user asynchronously, count is delivered to the supplied UnreadUpdatesCallback instance Note : This may return 0 or stale value when there is no network connectivity etc + public void getUnreadCountAsync(int callbackId); + + public void initNative(); + + //Attaches the given text as a breadcrumb to the conversations/tickets. + public void leaveBreadCrumb(String crumbText); + //Set the email of the user to be reported on the Freshdesk Portal + + public void setUserEmail(String email); + + //Set the name of the user to be reported on the Freshdesk Portal. + public void setUserFullName(String name); + + //Display the App Rating dialog with option to Rate, Leave feedback etc + public void showAppRateDialog(); + //Directly launch Conversation list screen from anywhere within the application + public void showConversations(); + + //Directly launch Feedback Screen from anywhere within the application. + public void showFeedbackWithArgs(String subject, String description); + //Directly launch Feedback Screen from anywhere within the application. + public void showFeedback(); + + //Displays the Support landing page (Solution Article List Activity) where only solutions tagged with the given tags are displayed. + public void showSolutionsWithTags(String tags, String separator); + + //Displays the Support landing page (Solution Article List Activity) from where users can do the following + //View solutions, + //Search solutions, + public void showSolutions(); + //Displays the Integrated Support landing page where only solutions tagged with the given tags are displayed. + public void showSupportWithTags(String tags, String separator); + + //Displays the Integrated Support landing page (Solution Article List Activity) from where users can do the following + //View solutions, + //Search solutions, + // Start a new conversation, + //View existing conversations update/ unread count etc + public void showSupport(); + } + +Notice also, that the native interface includes a set of methods with names prefixed with `config__`. This is just a naming conventions I used to identify methods that map to the `MobihelpConfig` class. I could have used a separate native interface for these, but decided to keep all the native stuff in one class for simplicity and maintainability. + +### Connecting the Public API to the Native Interface + +So we have a public API, and we have a native interface. The idea is that the public API should be a thin wrapper around the native interface to smooth out rough edges that are likely to exist due to the strict set of rules involved in native interfaces. We’ll, therefore, use delegation inside the `Mobihelp` class to provide it a reference to an instance of `MobihelpNative`: + + + public class Mobihelp { + private static MobihelpNative peer; + +We’ll initialize this `peer` inside the `init()` method of the `Mobihelp` class. Notice, though that `init()` is private since we have provided abstractions for the Android and iOS apps separately: + + + //Initialize the Mobihelp support section with necessary app configuration. + public final static void initAndroid(MobihelpConfig config) { + if ("and".equals(Display.getInstance().getPlatformName())) { + init(config); + } + } + + public final static void initIOS(MobihelpConfig config) { + if ("ios".equals(Display.getInstance().getPlatformName())) { + init(config); + } + } + + private static void init(MobihelpConfig config) { + peer = (MobihelpNative)NativeLookup.create(MobihelpNative.class); + peer.config_setAppId(config.getAppId()); + peer.config_setAppSecret(config.getAppSecret()); + peer.config_setAutoReplyEnabled(config.isAutoReplyEnabled()); + peer.config_setDomain(config.getDomain()); + peer.config_setEnhancedPrivacyModeEnabled(config.isEnhancedPrivacyModeEnabled()); + if (config.getFeedbackType() != null) { + peer.config_setFeedbackType(config.getFeedbackType().ordinal()); + } + peer.config_setLaunchCountForReviewPrompt(config.getLaunchCountForReviewPrompt()); + peer.config_setPrefetchSolutions(config.isPrefetchSolutions()); + peer.initNative(); + + } + +**Things to Notice** : + + 1. The `initAndroid()` and `initIOS()` methods include a check to see if they are running on the correct platform. Ultimately they both call `init()`. + + 2. The `init()` method, uses the `NativeLookup` class to instantiate our native interface. + +### Implementing the Glue Between Public API and Native Interface + +For most of the methods in the `Mobihelp` class, we can see that the public API will just be a thin wrapper around the native interface. E.g. the public API implementation of `setUserFullName(String)` is: + + + public final static void setUserFullName(String name) { + peer.setUserFullName(name); + } + +For some other methods, the public API needs to break apart the parameters into a form that the native interface can accept. E.g. the `init()` method, shown above, takes a `MobihelpConfig` object as a parameter, but it passed the properties of the `config` object individually into the native interface. + +Another example, is the `showSupport(ArrayList tags)` method. The corresponding native interface method that is wraps is `showSupport(String tags, String separator)` – i.e it needs to merge all tags into a single delimited string, and pass then to the native interface along with the delimiter used. The implementation is: + + + public final static void showSupport(ArrayList tags) { + String separator = findUnusedSeparator(tags); + StringBuilder sb = new StringBuilder(); + for (String tag : tags) { + sb.append(tag).append(separator); + } + peer.showSupportWithTags(sb.toString().substring(0, sb.length()-separator.length()), separator); + } + +The only other non-trivial wrapper is the `getUnreadCountAsync()` method that we discussed before: + + + public final static void getUnreadCountAsync(UnreadUpdatesCallback callback) { + int callbackId = MobihelpNativeCallback.registerUnreadUpdatesCallback(callback); + peer.getUnreadCountAsync(callbackId); + } + +## In the Next Instalment …​ + +In [part 2](http://www.codenameone.com/blog/integrating-3rd-party-native-sdks-part-2.html) of this series I’ll cover the native Android implementation, and part 3 will cover the native iOS implementation. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Steve Nganga** — September 29, 2015 at 4:43 pm ([permalink](https://www.codenameone.com/blog/integrating-3rd-party-native-sdks-part-1.html#comment-22265)) + +> just what i have been waiting for +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintegrating-3rd-party-native-sdks-part-1.html) + + +### **Moacir Schmidt** — October 18, 2015 at 3:37 pm ([permalink](https://www.codenameone.com/blog/integrating-3rd-party-native-sdks-part-1.html#comment-22219)) + +> Excellent! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintegrating-3rd-party-native-sdks-part-1.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/integrating-3rd-party-native-sdks-part-2.md b/docs/website/content/blog/integrating-3rd-party-native-sdks-part-2.md new file mode 100644 index 0000000000..fec09a2fb0 --- /dev/null +++ b/docs/website/content/blog/integrating-3rd-party-native-sdks-part-2.md @@ -0,0 +1,297 @@ +--- +title: Integrating 3rd Party Native SDKs Part II +slug: integrating-3rd-party-native-sdks-part-2 +url: /blog/integrating-3rd-party-native-sdks-part-2/ +original_url: https://www.codenameone.com/blog/integrating-3rd-party-native-sdks-part-2.html +aliases: +- /blog/integrating-3rd-party-native-sdks-part-2.html +date: '2015-10-04' +author: Steve Hannah +--- + +![Header Image](/blog/integrating-3rd-party-native-sdks-part-2/native-sdks-header.jpg) + +This blog post is part two in a three-part series on integrating 3rd party native SDKs into Codename One application. I recommend you start with part one in this series as it will give you much-needed context to understand the procedures described in part two and three. + +In [part one](http://www.codenameone.com/blog/integrating-3rd-party-native-sdks-part-1.html), we described the design and development of the public API and native interfaces of the Codename One FreshDesk library. In this installment we’ll move onto the development of the Android side of the native interface. + +## Step 5: Implementing the Native Interface in Android + +Now that we have set up our public API and our native interface, it is time to work on the native side of things. You can generate stubs for all platforms in your IDE (Netbeans in my case), by right clicking on the `MobihelpNative` class in the project explorer and selecting “Generate Native Access”. + +![c9d4b9cc 61f6 11e5 8b67 4691600188cd](/blog/integrating-3rd-party-native-sdks-part-2/c9d4b9cc-61f6-11e5-8b67-4691600188cd.png) + +This will generate a separate directory for each platform inside your project’s `native` directory: + +![eef6d078 61f6 11e5 91cd 2e1836916359](/blog/integrating-3rd-party-native-sdks-part-2/eef6d078-61f6-11e5-91cd-2e1836916359.png) + +Inside the `android` directory, this generates a `com/codename1/freshdesk/MobihelpNativeImpl` class with stubs for each method. + +Our implementation will be a thin wrapper around the native Android SDK. See the source [here](https://github.com/shannah/cn1-freshdesk/blob/master/cn1-freshdesk-demo/native/android/com/codename1/freshdesk/MobihelpNativeImpl.java). + +**Some highlights:** + + 1. `Context` : The native API requires us to pass a **context** object as a parameter on many methods. This should be the context for the current activity. It will allow the FreshDesk API to know where to return to after it has done its thing. Codename One provides a class called `AndroidNativeUtil` that allows us to retrieve the app’s Activity (which includes the Context). We’ll wrap this with a convenience method in our class as follows: + + private static Context context() { + return com.codename1.impl.android.AndroidNativeUtil.getActivity().getApplicationContext(); + } + +This will enable us to easily wrap the freshdesk native API. E.g.: + + public void clearUserData() { + com.freshdesk.mobihelp.Mobihelp.clearUserData(context()); + } + + 2. `runOnUiThread()` – Many of the calls to the FreshDesk API may have been made from the Codename One EDT. However, Android has its own event dispatch thread that should be used for interacting with native Android UI. Therefore, any API calls that look like they initiate some sort of native Android UI process should be wrapped inside Android’s `runOnUiThread()` method which is similar to Codename One’s `Display.callSerially()` method. E.g. see the `showSolutions()` method: + + public void showSolutions() { + activity().runOnUiThread(new Runnable() { + public void run() { + com.freshdesk.mobihelp.Mobihelp.showSolutions(context()); + } + }); + + } + +(Note here that the `activity()` method is another convenience method to retrieve the app’s current `Activity` from the `AndroidNativeUtil` class). + + 3. **Callbacks**. We discussed, in detail, the mechanisms we put in place to enable our native code to perform callbacks into Codename One. You can see the native side of this by viewing the `getUnreadCountAsync()` method implementation: + + public void getUnreadCountAsync(final int callbackId) { + activity().runOnUiThread(new Runnable() { + public void run() { + com.freshdesk.mobihelp.Mobihelp.getUnreadCountAsync(context(), new com.freshdesk.mobihelp.UnreadUpdatesCallback() { + public void onResult(com.freshdesk.mobihelp.MobihelpCallbackStatus status, Integer count) { + MobihelpNativeCallback.fireUnreadUpdatesCallback(callbackId, status.ordinal(), count); + } + }); + } + }); + + } + +## Step 6: Bundling the Native SDKs + +The last step (at least on the Android side) is to bundle the FreshDesk SDK. For Android, there are a few different scenarios you’ll run into for embedding SDKs: + + 1. **The SDK includes only Java classes** – NO XML UI files, assets, or resources that aren’t included inside a simple .jar file. In this case, you can just place the .jar file inside your project’s `native/android` directory. + + 2. **The SDK includes some XML UI files, resources, and assets.** In this case, the SDK is generally distributed as an Android project folder that can be imported into an Eclipse or Android studio workspace. In general, in this case, you would need to zip the entire directory and change the extension of the resulting .zip file to “.andlib”, and place this in your project’s `native/android` directory. + + 3. **The SDK is distributed as an`.aar` file** – In this case you can just copy the `.aar` file into your `native/android` directory. + +### The FreshDesk SDK + +The FreshDesk (aka Mobihelp) SDK is distributed as a project folder (i.e. scenario 2 from the above list). Therefore, our procedure is to download the SDK ([download link](https://s3.amazonaws.com/assets.mobihelp.freshpo.com/sdk/mobihelp_sdk_android.zip)), and rename it from `mobihelp_sdk_android.zip` to `mobihelp_sdk_android.andlib`, and copy it into our `native/android` directory. + +#### Dependencies + +Unfortunately, in this case there’s a catch. The Mobihelp SDK includes a dependency: + +> Mobihelp SDK depends on AppCompat-v7 (Revision 19.0+) Library. You will need to update project.properties to point to the Appcompat library. + +If we look inside the `project.properties` file (inside the Mobihelp SDK directory— i.e. you’d need to extract it from the zip to view its contents), you’ll see the dependency listed: + + + android.library.reference.1=../appcompat_v7 + +I.e. it is expecting to find the `appcompat_v7` library located in the same parent directory as the Mobihelp SDK project. After a little bit of research (if you’re not yet familiar with the Android AppCompat support library), we find that the `AppCompat_v7` library is part of the Android Support library, which can can installed into your local Android SDK using Android SDK Manager. [Installation processed specified here](https://developer.android.com/tools/support-library/setup.html). + +After installing the support library, you need to retrieve it from your Android SDK. You can find that .aar file inside the `ANDROID_HOME/sdk/extras/android/m2repository/com/android/support/appcompat-v7/19.1.0/` directory (for version 19.1.0). The contents of that directory on my system are: + + + appcompat-v7-19.1.0.aar appcompat-v7-19.1.0.pom + appcompat-v7-19.1.0.aar.md5 appcompat-v7-19.1.0.pom.md5 + appcompat-v7-19.1.0.aar.sha1 appcompat-v7-19.1.0.pom.sha1 + +There are two files of interest here: + + 1. appcompat-v7-19.1.0.aar – This is the actual library that we need to include in our project to satisfy the Mobisdk dependency. + + 2. appcompat-v7-19.1.0.pom – This is the Maven XML file for the library. It will show us any dependencies that the appcompat library has. We will also need to include these dependencies: + + + + com.android.support + support-v4 + 19.1.0 + compile + + + +i.e. We need to include the `support-v4` library version 19.1.0 in our project. This is also part of the Android Support library. If we back up a couple of directories to: `ANDROID_HOME/sdk/extras/android/m2repository/com/android/support`, we’ll see it listed there: + + appcompat-v7 palette-v7 + cardview-v7 recyclerview-v7 + gridlayout-v7 support-annotations + leanback-v17 support-v13 + mediarouter-v7 support-v4 + multidex test + multidex-instrumentation + +\+ And if we look inside the appropriate version directory of `support-v4` (in `ANDROID_HOME/sdk/extras/android/m2repository/com/android/support/support-v4/19.1.0`), we see: + + support-v4-19.1.0-javadoc.jar support-v4-19.1.0.jar + support-v4-19.1.0-javadoc.jar.md5 support-v4-19.1.0.jar.md5 + support-v4-19.1.0-javadoc.jar.sha1 support-v4-19.1.0.jar.sha1 + support-v4-19.1.0-sources.jar support-v4-19.1.0.pom + support-v4-19.1.0-sources.jar.md5 support-v4-19.1.0.pom.md5 + support-v4-19.1.0-sources.jar.sha1 support-v4-19.1.0.pom.sha1 + +Looks like this library is pure Java classes, so we only need to include the `support-v4-19.1.0.jar` file into our project. Checking the `.pom` file we see that there are no additional dependencies we need to add. + +So, to summarize our findings, we need to include the following files in our `native/android` directory: + + 1. appcompat-v7-19.1.0.aar + + 2. support-v4-19.1.0.jar + +And since our Mobihelp SDK lists the appcompat_v7 dependency path as “../appcompat_v7” in its project.properties file, we are going to rename `appcompat-v7-19.1.0.aar` to `appcompat_v7.aar`. + +When all is said and done, our `native/android` directory should contain the following: + + + appcompat_v7.aar mobihelp.andlib + com support-v4-19.1.0.jar + +## Step 7 : Injecting Android Manifest and Proguard Config + +The final step on the Android side is to inject necessary permissions and services into the project’s AndroidManifest.xml file. + +We can find the manifest file injections required by opening the `AndroidManifest.xml` file from the MobiHelp SDK project. Its contents are as follows: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +We’ll need to add the `` tags and all of the contents of the `` tag to our manifest file. Codename One provides the following build hints for these: + + 1. `android.xpermissions` – For your `` directives. Add a build hint with name `android.xpermissions`, and for the value, paste the actual `` XML tag. + + 2. `android.xapplication` – For the contents of your `` tag. + +### Proguard Config + +For the release build, we’ll also need to inject some proguard configuration so that important classes don’t get stripped out at build time. The FreshDesk SDK instructions state: + +> If you use Proguard, please make sure you have the following included in your project’s proguard-project.txt +> +> +> -keep class android.support.v4.** { *; } +> -keep class android.support.v7.** { *; } + +In addition, if you look at the `proguard-project.txt` file inside the Mobihelp SDK, you’ll see the rules: + + + -keep public class * extends android.app.Service + -keep public class * extends android.content.BroadcastReceiver + -keep public class * extends android.app.Activity + -keep public class * extends android.preference.Preference + -keep public class com.freshdesk.mobihelp.exception.MobihelpComponentNotFoundException + + -keepclassmembers class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; + } + +We’ll want to merge this and then paste them into the build hint `android.proguardKeep` of our project. + +## Troubleshooting Android Stuff + +If, after doing all this, your project fails to build, you can enable the “Include Source” option of the build server, then download the source project, open it in Eclipse or Android Studio, and debug from there. + +## In Our Next Instalment…​ + +In the third and final part of this blog series, we will shift our focus to the iOS side of the library. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/integrating-3rd-party-native-sdks-part-3.md b/docs/website/content/blog/integrating-3rd-party-native-sdks-part-3.md new file mode 100644 index 0000000000..9bd2d39a56 --- /dev/null +++ b/docs/website/content/blog/integrating-3rd-party-native-sdks-part-3.md @@ -0,0 +1,141 @@ +--- +title: Integrating 3rd Party Native SDKs Part III +slug: integrating-3rd-party-native-sdks-part-3 +url: /blog/integrating-3rd-party-native-sdks-part-3/ +original_url: https://www.codenameone.com/blog/integrating-3rd-party-native-sdks-part-3.html +aliases: +- /blog/integrating-3rd-party-native-sdks-part-3.html +date: '2015-10-11' +author: Steve Hannah +--- + +![Header Image](/blog/integrating-3rd-party-native-sdks-part-3/native-sdks-header.jpg) + +This is the third and final instalment in a series on integrating 3rd party native SDKs in your Codename One application. If you missed the first two chapters, I recommend you begin with part one before reading this tutorial, as it provides much needed context for the procedures described here. + +## Part 2: Implementing the iOS Native Code + +Part 1 of this tutorial focused on the Android native integration. Now we’ll shift our focus to the iOS implementation. + +After selecting “Generate Native Interfaces” for our “MobihelpNative” class, you’ll find a `native/ios` directory in your project with the following files: + + 1. [`com_codename1_freshdesk_MobihelpNativeImpl.h`](https://github.com/shannah/cn1-freshdesk/blob/master/cn1-freshdesk-demo/native/ios/com_codename1_freshdesk_MobihelpNativeImpl.h) + + 2. [`com_codename1_freshdesk_MobihelpNativeImpl.m`](https://github.com/shannah/cn1-freshdesk/blob/master/cn1-freshdesk-demo/native/ios/com_codename1_freshdesk_MobihelpNativeImpl.m) + +These files contain stub implementations corresponding to our `MobihelpNative` class. + +We make use of the [API docs](http://developer.freshdesk.com/mobihelp/ios/api/) to see how the native SDK needs to be wrapped. The method names aren’t the same. E.g. instead of a method `showFeedback()`, it has a message `-presentFeedback:` + +We more-or-less just follow the [iOS integration guide](http://developer.freshdesk.com/mobihelp/ios/integration_guide/#getting-started) for wrapping the API. Some key points include: + + 1. Remember to import the `Mobihelp.h` file in your header file: + + #import "Mobihelp.h" + + 2. Similar to our use of `runOnUiThread()` in Android, we will wrap all of our API calls in either `dispatch_async()` or `dispatch_sync()` calls to ensure that we are interacting with the Mobihelp API on the app’s main thread rather than the Codename One EDT. + + 3. Some methods/messages in the Mobihelp SDK require us to pass a `UIViewController` as a parameter. In Codename One, the entire application uses a single UIViewController: `CodenameOne_GLViewController`. You can obtain a reference to this using the `[CodenameOne_GLViewController instance]` message. We need to import its header file: + + #import "CodenameOne_GLViewController.h" + +As an example, let’s look at the `showFeedback()` method: + + -(void)showFeedback{ + + dispatch_async(dispatch_get_main_queue(), ^{ + [[Mobihelp sharedInstance] presentFeedback:[CodenameOne_GLViewController instance]]; + }); + } + +### Using the `MobihelpNativeCallback` + +We described earlier how we created a static method on the `MobihelpNativeCallback` class so that native code could easily fire a callback method. Now let’s take a look at how this looks from the iOS side of the fence. Here is the implementation of `getUnreadCountAsync()`: + + + -(void)getUnreadCountAsync:(int)param{ + dispatch_async(dispatch_get_main_queue(), ^{ + [[Mobihelp sharedInstance] unreadCountWithCompletion:^(NSInteger count){ + com_codename1_freshdesk_MobihelpNativeCallback_fireUnreadUpdatesCallback___int_int_int(CN1_THREAD_GET_STATE_PASS_ARG param, 3 /*SUCCESS*/, count); + }]; + }); + } + +In our case the iOS SDK version of this method is `+unreadCountWithCompletion:` which takes a block (which is like an anonymous function) as a parameter. + +The callback to our Codename One function occurs on this line: + + + com_codename1_freshdesk_MobihelpNativeCallback_fireUnreadUpdatesCallback___int_int_int(CN1_THREAD_GET_STATE_PASS_ARG param, 3 /*SUCCESS*/, count); + +**Some things worth mentioning here:** + + 1. The method name is the result of taking the FQN (`com.codename1.freshdesk.MobihelpNativeCallback.fireUpdateUnreadUpdatesCallback(int, int, int)`) and replacing all `.` characters with underscores, suffixing two underscores after the end of the method name, then appending `_int` once for each of the `int` arguments. + + 2. We also need to import the header file for this class: + + #import "com_codename1_freshdesk_MobihelpNativeCallback.h" + +## Bundling Native iOS SDK + +Now that we have implemented our iOS native interface, we need to bundle the Mobihelp iOS SDK into our project. There are a few different scenarios you may face when looking to include a native SDK: + + 1. The SDK includes `.bundle` resource files. In this case, just copy the `.bundle` file(s) into your `native/ios` directory. + + 2. The SDK includes `.h` header files. In this case, just copy the `.h` file(s) into your `native/ios` directory. + + 3. The SDK includes `.a` files. In this case, just copy the `.a` file(s) into your `native/ios` directory. + + 4. The SDK includes `.framework` files. This is a bit tricker as Codename One doesn’t support simply copying the `.framework` files inside your project. In this case you need to perform the following: + + 5. Right click on the `.framework` file (if you are using OS X) and select “Show Package Contents”. + + 6. Find the “binary” file within the framework, and copy it into your `native/ios` directory – but rename it `libXXX.a` (where XXX is the name of the binary). + + 7. Copy all `.h` files from the framework into your `native/ios` directory. + + 8. Update all `#import` statements in the headers from `#import ` format to simply `#import "FileName.h"` + +The FreshDesk SDK doesn’t include any `.framework` files, so we don’t need to worry about that last scenario. We simply [download the iOS SDK](https://s3.amazonaws.com/assets.mobihelp.freshpo.com/sdk/mobihelp_sdk_ios.zip), copy the `libFDMobihelpSDK.a`, `Mobihelp.h`. `MHModel.bundle`, `MHResources.bundle`, and `MHLocalization/en.proj/MHLocalizable.strings` into `native/ios`. + +## Troubleshooting iOS + +If you run into problems with the build, you can select “Include Sources” in the build server to download the resulting Xcode Project. You can then debug the Xcode project locally, make changes to your iOS native implementation files, and copy them back into your project once it is building properly. + +## Adding Required Core Libraries and Frameworks + +The iOS integration guide for the FreshDesk SDK lists the following core frameworks as dependencies: + +![12c5303e 620c 11e5 9dbb bcb4bebc0c87](/blog/integrating-3rd-party-native-sdks-part-3/12c5303e-620c-11e5-9dbb-bcb4bebc0c87.png) + +We can add these dependencies to our project using the `ios.add_libs` build hint. E.g. + +![65e31df8 620c 11e5 87ff 6b926a3f2090](/blog/integrating-3rd-party-native-sdks-part-3/65e31df8-620c-11e5-87ff-6b926a3f2090.png) + +I.e. we just list the framework names separated by semicolons. Notice that my list in the above image doesn’t include all of the frameworks that they list because many of the frameworks are already included by default (I obtained the default list by simply building the project with “include sources” checked, then looked at the frameworks that were included). + +# Part 3 : Packaging as a .cn1lib + +During the initial development, I generally find it easier to use a regular Codename One project so that I can run and test as I go. But once it is stabilized, and I want to distribute the library to other developers, I will transfer it over to a Codename One library project. This general process involves: + + 1. Create a Codename One Library project. + + 2. Copy the .java files from my original project into the library project. + + 3. Copy the `native` directory from the original project into the library project. + + 4. Copy the **relevant** build hints from the original project’s `codenameone_settings.properties` file into the library project’s `codenameone_library_appended.properties` file. + +In the case of the FreshDesk .cn1lib, I modified the original project’s build script to generate and build a libary project automatically. But that is beyond the scope of this tutorial. + +## Summary + +After walking through this tutorial, you should have all the required knowledge to wrap native SDKs into your own codename one libraries. Wrapping native SDKs is a really easy way to extend the capabilities of the Codename One platform. If you plan to create such a library, I encourage you to blog about it and post your experiences to the Codename One google group. We’re always interested in hearing how the community is using Codename One, and we’re especially interested in hearing about the creative ways that you are extending it. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/integrating-android-3rd-party-libraries-jni.md b/docs/website/content/blog/integrating-android-3rd-party-libraries-jni.md new file mode 100644 index 0000000000..4839a67561 --- /dev/null +++ b/docs/website/content/blog/integrating-android-3rd-party-libraries-jni.md @@ -0,0 +1,115 @@ +--- +title: Integrating Android 3rd Party Libraries & JNI +slug: integrating-android-3rd-party-libraries-jni +url: /blog/integrating-android-3rd-party-libraries-jni/ +original_url: https://www.codenameone.com/blog/integrating-android-3rd-party-libraries-jni.html +aliases: +- /blog/integrating-android-3rd-party-libraries-jni.html +date: '2015-03-03' +author: Chen Fishbein +--- + +![Header Image](/blog/integrating-android-3rd-party-libraries-jni/binary.png) + +![](/blog/integrating-android-3rd-party-libraries-jni/binary.png) + +While its pretty easy to use [native interfaces](http://www.codenameone.com/how-do-i---access-native-device-functionality-invoke-native-interfaces.html) +to write Android native code some things aren’t necessarily as obvious. E.g. if you want to integrate a 3rd party library, specifically one that includes native C JNI code this process is somewhat undocumented. +If you need to integrate such a library into your native calls you have the following 3 options: + + 1. The first option (and the easiest one) is to just place a Jar file in the native/android directory. +This will link your binary with the jar file. Just place the jar under the native/android and the build server will pick it up and will add it to the classpath. +Notice that Android release apps are obfuscated by default which might cause issues with such libraries if they reference API’s that are unavailable on Android. +You can workaround this by adding a build hint to the proguard obfuscation code that blocs the obfuscation of the problematic classes using the build hint: + + android.proguardKeep=-keep class com.mypackage.ProblemClass { *; } + + 2. The second option is to add an Android Library Project. Not all 3rd parties can be packaged as a simple jar, some 3rd parties needs to declare +Activities add permissions, resources, assets, and/or even add native code (.so files). To link a Library project to your CN1 project open the Library +project in Eclipse or Android Studio and make sure the project builds, after the project was built successfully remove the bin directory from the +project and zip the whole project. +Rename the extension of the zip file to .andlib and place the andlib file under native/android directory. The build server will pick it up and will link it to the project. + 3. We recently added a 3rd option :aar files. The aar file is a binary format from Google that represents an Android Library project. One of the problem with +the Android Library projects was the fact that it required the project sources which made it difficult for 3rd party vendors to publish libraries, so android +introduced the aar file which is a binary format that represents a Library project. To learn more about arr you can read +[this](http://tools.android.com/tech-docs/new-build-system/aar-format). + +You can link an aar file by placing it under the native/android and the build server will link it to the project. + +To use any of the options above 3rd parties API’s you will need to create a +[ NativeInterface](http://www.codenameone.com/how-do-i---access-native-device-functionality-invoke-native-interfaces.html) and access +the libs API’s under the android implementation only section. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — June 29, 2015 at 10:49 am ([permalink](https://www.codenameone.com/blog/integrating-android-3rd-party-libraries-jni.html#comment-21599)) + +> Chidiebere Okwudire says: +> +> Hi Chen, +> +> Under option 1, can you elaborate what you mean by “API’s that are unavailable on Android” when talking about obfuscation? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintegrating-android-3rd-party-libraries-jni.html) + + +### **John Markh** — January 18, 2017 at 7:13 pm ([permalink](https://www.codenameone.com/blog/integrating-android-3rd-party-libraries-jni.html#comment-23235)) + +> John Markh says: +> +> I would be great to have a code example to, for example, using Android PackageManager to retrieve a list of installed applications. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintegrating-android-3rd-party-libraries-jni.html) + + +### **Shai Almog** — January 19, 2017 at 6:15 am ([permalink](https://www.codenameone.com/blog/integrating-android-3rd-party-libraries-jni.html#comment-24120)) + +> Shai Almog says: +> +> There are quite a few samples in the cn1libs section where pretty much all the libraries are open source. +> +> Using this query on github I was able to find several results: [https://github.com/search?q…]([https://github.com/search?q=codename1+PackageManager&type=Code&utf8=%E2%9C%93](https://github.com/search?q=codename1+PackageManager&type=Code&utf8=%E2%9C%93)) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintegrating-android-3rd-party-libraries-jni.html) + + +### **Shai Almog** — January 19, 2017 at 6:17 am ([permalink](https://www.codenameone.com/blog/integrating-android-3rd-party-libraries-jni.html#comment-23146)) + +> Shai Almog says: +> +> Hi, +> sorry for the late reply. Not sure why Chen didn’t answer back then… +> +> A JAR might import javax.swing and use it for some cases but might handle that case correctly by catching the class not found exception. However, this might collide with obfuscation that doesn’t like those sort of tricks… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintegrating-android-3rd-party-libraries-jni.html) + + +### **Amina Benzerga** — July 13, 2017 at 3:31 pm ([permalink](https://www.codenameone.com/blog/integrating-android-3rd-party-libraries-jni.html#comment-23516)) + +> Amina Benzerga says: +> +> the query does not work anymore, could you please give me a example? Thank you 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintegrating-android-3rd-party-libraries-jni.html) + + +### **Shai Almog** — July 14, 2017 at 6:35 am ([permalink](https://www.codenameone.com/blog/integrating-android-3rd-party-libraries-jni.html#comment-21393)) + +> Shai Almog says: +> +> I see 11 results in the link above +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintegrating-android-3rd-party-libraries-jni.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/intercepting-urls-on-ios-android.md b/docs/website/content/blog/intercepting-urls-on-ios-android.md new file mode 100644 index 0000000000..dc091e8f82 --- /dev/null +++ b/docs/website/content/blog/intercepting-urls-on-ios-android.md @@ -0,0 +1,177 @@ +--- +title: Intercepting URL's On iOS & Android +slug: intercepting-urls-on-ios-android +url: /blog/intercepting-urls-on-ios-android/ +original_url: https://www.codenameone.com/blog/intercepting-urls-on-ios-android.html +aliases: +- /blog/intercepting-urls-on-ios-android.html +date: '2014-07-15' +author: Shai Almog +--- + +![Header Image](/blog/intercepting-urls-on-ios-android/intercepting-urls-on-ios-android-1.png) + + + + + +![Picture](/blog/intercepting-urls-on-ios-android/intercepting-urls-on-ios-android-1.png) + + + + +** +Notice: +** +the original version of this post incorrectly specified the property as AppArgs instead of AppArg. This is now fixed. For Android you would probably also want to add the build argument android.xactivity=android:exported=”false”. + + + + + + +A common trick in mobile application development, is communication between two unrelated applications. In Android we have intents which are pretty elaborate and can be used via Display.execute, however what if you would like to expose the functionality of your application to a different application running on the device. This would allow that application to launch your application. + + +This isn’t something we builtin to Codename One, however we did expose enough of the platform capabilities to enable that functionality rather easily on Android. + + + + +On Android we need to define an intent filter which we can do using the android.xintent_filter build argument, this accepts the XML to filter whether a request is relevant to our application: + + +android.xintent_filter= + + + + + + + + + +This is taken from this +[ +stack overflow question +](http://stackoverflow.com/questions/11421048/android-ios-custom-uri-protocol-handling) +, to bind the myapp:// URL to your application. So if you will type myapp://x into the Android browser your application will launch. + + + + +So how do you get the “launch arguments”, passed to your application? + + + + +Display.getInstance().getProperty(“AppArg”) should contain the value of the URL that launched the app or would be null if it was launched via the icon. + + + + + + + + + + +iOS is practically identical with some small caveats, iOS’s equivalent of the manifest is the plist. So we allow injecting more data into the plist thru the + + +ios.plistInject build argument. + + + +So the equivalent in the iOS side would be ios.plistInject=CFBundleURLTypes CFBundleURLName com.yourcompany.myapp CFBundleURLSchemes myapp + + + + +On a separate unrelated note the guys from Java Code Geeks announced the winners of +[ +our raffle of two tickets +](http://www.javacodegeeks.com/2014/06/codename-one-java-code-geeks-are-giving-away-free-javaone-tickets-worth-3300.html) +, yesterday. Congratulations to both winners! + + + + + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — August 12, 2017 at 10:56 am ([permalink](https://www.codenameone.com/blog/intercepting-urls-on-ios-android.html#comment-23753)) + +> Francesco Galgani says: +> +> It seems an old post. I’m interested in intercepting URLs on iOS & Android because an use case like this: +> +> 1\. The server sends a verification code to a given phone number by sms +> 2\. Because Codename One cannot receive sms, the verification code can be taken by the app when the user tape the url inside the sms. +> +> Of course I can have different use cases, all with the purpose to pass one or more arguments to my app from an external app (native sms app, other sms/messaging apps like Signal or Whatsapp, browsers, etc.). +> +> So, my questions are if this post is still update and if it’s correctly formatted (it’s not clear if the build arguments for Android and iOS are in only one row). +> +> I suppose that the build arguments are the ones described in “Sending Arguments To The Build Server”, is it right? +> [https://www.codenameone.com…]() +> +> Thank you. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintercepting-urls-on-ios-android.html) + + +### **Shai Almog** — August 13, 2017 at 5:32 am ([permalink](https://www.codenameone.com/blog/intercepting-urls-on-ios-android.html#comment-23424)) + +> Shai Almog says: +> +> This post is in the developer guide too (I think under the misc section). Everything is in one row since that’s how build hints work. Since it’s XML it doesn’t matter. +> +> SMS and URL interception are very different things. If you look at apps like banking apps, uber, whatsapp etc. in all of them SMS activation is done by typing in the value you get from the native SMS app. Some rare apps catch the incoming SMS on Android but since this requires some pretty scary sounding permissions a lot of apps just give up on that feature and work the same way as they do on iOS. +> +> This can be done easily in Codename One and is done by the JAT app. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintercepting-urls-on-ios-android.html) + + +### **Francesco Galgani** — July 11, 2018 at 6:22 pm ([permalink](https://www.codenameone.com/blog/intercepting-urls-on-ios-android.html#comment-23649)) + +> Francesco Galgani says: +> +> At the begging of this post, you wrote: «For Android you would probably also want to add the build argument android.xactivity=android:exported=”false”». Indeed this build hint cannot be used, because it causes that Android cannot start the app, giving the error: “The app is not installed”. The reason is explained here: [https://stackoverflow.com/a…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintercepting-urls-on-ios-android.html) + + +### **Shai Almog** — July 12, 2018 at 5:39 am ([permalink](https://www.codenameone.com/blog/intercepting-urls-on-ios-android.html#comment-23986)) + +> Shai Almog says: +> +> I don’t recall this at all, it’s been 4 years since I wrote that so no idea… +> +> This isn’t mentioned in the developer guide section though: [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintercepting-urls-on-ios-android.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/intercom-support.md b/docs/website/content/blog/intercom-support.md new file mode 100644 index 0000000000..8b53ae7b95 --- /dev/null +++ b/docs/website/content/blog/intercom-support.md @@ -0,0 +1,43 @@ +--- +title: Intercom Support +slug: intercom-support +url: /blog/intercom-support/ +original_url: https://www.codenameone.com/blog/intercom-support.html +aliases: +- /blog/intercom-support.html +date: '2017-02-01' +author: Shai Almog +--- + +![Header Image](/blog/intercom-support/new-features-2.jpg) + +We use [intercom.io](http://intercom.io) for our website support system you can see it as the chat button on the bottom right of the page. The true value of this tool is in it’s ability to deliver a unified interface everywhere, normally this stretches into native mobile apps as well. As a result we decided to port the native intercom device API to Codename One so it will be easy to deploy everywhere. + +We added a new [cn1lib for intercom](https://github.com/codenameone/IntercomSupport/), it works on Android/iOS and will allow you to communicate with users of your app thru the app and web. It also allows for more advanced event based automation which is really useful when building a user funnel. + +To get started install the cn1lib thru the extensions menu as usual. Then assuming you have an intercom.io account create Android/iOS apps there. From there you can get the keys for Android/iOS and use the following to activate intercom: + + + Intercom.init("AndroidAppKey", "IosAppKey", "AppId"); + +Assuming intercom is supported on the platform `Intercom.getInstance()` will return a non-null value. You need to start by registering your user, if your app allows for login you can use the email or other credential you might have for binding the user identity using something like: + + + Intercom.getInstance().registerIdentifiedUser(Registration.create().withEmail(usersEmail)); + +If not you can use `registerUnidentifiedUser()`. + +__ | You **MUST** register before using other API’s +---|--- + +Once you are registered you can check for messages and show the compose/discussion threads. You can use a UI like `FloatingActionButton` to trigger a chat with support etc. + +Integrating Intercom was **very** easy, I’ll write some more about it next week. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/intro-to-in-app-purchase.md b/docs/website/content/blog/intro-to-in-app-purchase.md new file mode 100644 index 0000000000..34d87c9bab --- /dev/null +++ b/docs/website/content/blog/intro-to-in-app-purchase.md @@ -0,0 +1,223 @@ +--- +title: Introduction to In-App Purchase +slug: intro-to-in-app-purchase +url: /blog/intro-to-in-app-purchase/ +original_url: https://www.codenameone.com/blog/intro-to-in-app-purchase.html +aliases: +- /blog/intro-to-in-app-purchase.html +date: '2016-12-13' +author: Steve Hannah +--- + +![Header Image](/blog/intro-to-in-app-purchase/in-app-purchase.jpg) + +__ | This is the first post in a three-part series on In-App purchase. Please check out [Part 2: Introduction to In-App Purchase](https://www.codenameone.com/blog/in-app-purchase-non-renewable-subscriptions.html) and [Part 3: Auto-renewing Subscriptions in iOS and Android](https://www.codenameone.com/blog/autorenewing-subscriptions-in-ios-and-android.html). +---|--- + +In-app purchase is a helpful tool for making app development profitable. Codename One has supported in-app purchases of consumable and non-consumable products on Android and iOS for some time now, and with the next update we are adding support for subscriptions. For such a seemingly simple task, in-app purchase involves a lot of moving parts – especially when it comes to subscriptions. For this reason, I’ll be splitting this topic up into a few different blog posts. This post will provide a light introduction to in-app purchase and subscriptions, and show you how to support them in your app. In subsequent posts, I’ll go deeper into some more advanced topics such as receipt validation, server-side subscription management (which is required for subscriptions in the iTunes store), and the specifics of how to set up in-app purchases in both Google Play and the iTunes stores. + +## The SKU + +In-app purchase support is centered around your set of SKUs that you want to sell. Each product that you sell, whether it be a 1-month subscription, an upgrade to the “Pro” version, “10 disco credits”, will have a SKU (stock-keeping-unit). Ideally you will be able to use the same SKU across all of the stores that you sell your app in. + +## Types of Products + +There are generally 4 classifications for products: + + 1. **Non-consumable Product** – This is a product that the user purchases once, and they “own” it. They cannot re-purchase it. One example is a product that upgrades your app to a “Pro” version. + + 2. **Consumable Product** – This is a product that the user can purchase multiple times. E.g. You might have a product for “10 Credits” that allow the user to buy things in a game. + + 3. **Non-Renewable Subscription** – A subscription that is purchased once, and will not be “auto-renewed” by the app store. These are almost identical to consumable products, except that subscriptions need to be transferable across all of the user’s devices. This means that non-renewable subscriptions require that you have a server server to keep track of the subscriptions. + + 4. **Renewable Subscriptions** – A subscription that is completely managed by the app store. The user will be automatically billed when the subscription period ends, and the subscription will be renewed. + +__ | These subscription categories may not be explicitly supported by a given store, or they may be called different things. However each type of product can be implemented in a Codename One app in a cross-platform way. E.g. In Google Play there is no distinction between consumable products and non-renewable subscriptions, but in iTunes there is a distinction. +---|--- + +## The “Hello World” of In-App Purchase + +Let’s start with a simple example of an app that sells “Worlds”. The first thing we do is pick the SKU for our product. I’ll choose “com.codename1.world” for the SKU. + + + public static final String SKU_WORLD = "com.codename1.world"; + +Next, our app’s main class needs to implement the `PurchaseCallback` interface + + + public class HelloWorldIAP implements PurchaseCallback { + .... + + @Override + public void itemPurchased(String sku) { + ... + } + + @Override + public void itemPurchaseError(String sku, String errorMessage) { + ... + } + + @Override + public void itemRefunded(String sku) { + ... + } + + @Override + public void subscriptionStarted(String sku) { + ... + } + + @Override + public void subscriptionCanceled(String sku) { + ... + } + + @Override + public void paymentFailed(String paymentCode, String failureReason) { + ... + } + + @Override + public void paymentSucceeded(String paymentCode, double amount, String currency) { + ... + } + + } + +Using these callbacks, we’ll be notified whenever something changes in our purchases. For our simple app we’re only interested in `itemPurchased()` and `itemPurchaseError()`. + +Now in the start method, we’ll add a button that allows the user to buy the world: + + + public void start() { + if(current != null){ + current.show(); + return; + } + Form hi = new Form("Hi World"); + Button buyWorld = new Button("Buy World"); + buyWorld.addActionListener(e->{ + if (Purchase.getInAppPurchase().wasPurchased(SKU_WORLD)) { + Dialog.show("Can't Buy It", "You already Own It", "OK", null); + } else { + Purchase.getInAppPurchase().purchase(SKU_WORLD); + } + }); + + hi.addComponent(buyWorld); + hi.show(); + } + +At this point, we already have a functional app that will track the sale of the world. To make it more interesting, let’s just add some feedback with the ToastBar to show when the purchase completes. + + + @Override + public void itemPurchased(String sku) { + ToastBar.showMessage("Thanks. You now own the world", FontImage.MATERIAL_THUMB_UP); + } + + @Override + public void itemPurchaseError(String sku, String errorMessage) { + ToastBar.showErrorMessage("Failure occurred: "+errorMessage); + } + +[See full code listing](https://gist.github.com/shannah/c38d18a1f3524a4a7e8d08d2731cfac7) + +__ | You can test out this code in the simulator without doing any additional setup and it will work. If you want the code to work properly on Android and iOS, you’ll need to set up the app and in-app purchase settings in the Google Play and iTunes stores respectively. I will cover that in a subsequent post. +---|--- + +When the app first opens we see our button: + +![In-app purchase demo app](/blog/intro-to-in-app-purchase/iap-demo-1.png) + +In the simulator, clicking on the “Buy World” button will bring up a prompt to ask you if you want to approve the purchase. + +![Approving the purchase in the simulator](/blog/intro-to-in-app-purchase/iap-demo2.png) + +Now if I try to buy the product again, it pops up the dialog to let me know that I already own it. + +![In App purchase already owned](/blog/intro-to-in-app-purchase/iap-demo3.png) + +## Making it Consumable + +In the “Buy World” example above, the “world” product was non-consumable, since it could only be purchased once. We could easily change it to a consumable product by simply disregarding whether it had been purchased before and keeping track of how many times it had been purchased. + +We’ll use storage to keep track of the number of worlds that have been purchased. We need two methods to manage this count. One to get the number of worlds that we currently own, and another to add a world to this count. + + + private static final String NUM_WORLDS_KEY = "NUM_WORLDS.dat"; + public int getNumWorlds() { + synchronized (NUM_WORLDS_KEY) { + Storage s = Storage.getInstance(); + if (s.exists(NUM_WORLDS_KEY)) { + return (Integer)s.readObject(NUM_WORLDS_KEY); + } else { + return 0; + } + } + } + + public void addWorld() { + synchronized (NUM_WORLDS_KEY) { + Storage s = Storage.getInstance(); + int count = 0; + if (s.exists(NUM_WORLDS_KEY)) { + count = (Integer)s.readObject(NUM_WORLDS_KEY); + } + count++; + s.writeObject(NUM_WORLDS_KEY, new Integer(count)); + } + } + +Now we’ll change our purchase code as follows: + + + buyWorld.addActionListener(e->{ + if (Dialog.show("Confirm", "You own "+getNumWorlds()+ + " worlds. Do you want to buy another one?", "Yes", "No")) { + Purchase.getInAppPurchase().purchase(SKU_WORLD); + } + }); + +And our `itemPurchased()` callback will need to add a world: + + + @Override + public void itemPurchased(String sku) { + addWorld(); + ToastBar.showMessage("Thanks. You now own "+getNumWorlds()+" worlds", FontImage.MATERIAL_THUMB_UP); + } + +[Show full code listing](https://gist.github.com/shannah/9a7bd06951207101918ad93fa809ee56) + +__ | When we eventually set up the products in the iTunes store we will need to mark the product as a consumable product or iTunes will prevent us from purchasing it multiple times. +---|--- + +## Next Up: Non-Renewable Subscriptions + +Read more: [Part 2: Introduction to In-App Purchase](https://www.codenameone.com/blog/in-app-purchase-non-renewable-subscriptions.html) +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **salah Alhaddabi** — December 28, 2016 at 7:38 pm ([permalink](https://www.codenameone.com/blog/intro-to-in-app-purchase.html#comment-23026)) + +> Very nice Steve. +> +> CN1 is an amazing framework for mobile apps really!! +> +> Please continue with these posts they are the best!! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintro-to-in-app-purchase.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/introducing-cloud-connect.md b/docs/website/content/blog/introducing-cloud-connect.md new file mode 100644 index 0000000000..1eddc8f034 --- /dev/null +++ b/docs/website/content/blog/introducing-cloud-connect.md @@ -0,0 +1,98 @@ +--- +title: Introducing Cloud Connect +slug: introducing-cloud-connect +url: /blog/introducing-cloud-connect/ +original_url: https://www.codenameone.com/blog/introducing-cloud-connect.html +aliases: +- /blog/introducing-cloud-connect.html +date: '2018-11-19' +author: Shai Almog +--- + +![Header Image](/blog/introducing-cloud-connect/codename-one-build.jpg) + +A few years back we had Codename One LIVE! +It allowed developers to preview designs built with the old GUI builder on devices. Today we’re introducing the equivalent functionality for the new GUI builder and the Codename One Build app. Cloud Connect allows you to instantly see changes from the GUI builder in the app. + +You can activate Cloud Connect using the new Cloud Connect button in the latest version of the GUI builder. Once it’s activated launch Codename One Build and open the side menu, you should see a new Cloud Connect option in the side menu. + +__ | You might need to kill and relaunch the app the first time around to make that menu appear +---|--- + +Check out the new [How Do I video](/how-do-i-use-cloud-connect.html) that covers the whole process. + +This is a remarkably useful feature as it allows us to instantly see the nuanced impact of choices we make within the GUI builder. Small alignment or boundary choices within the tool can have a significant impact when you’re running on the device. Fonts and styles can look very different on the physical device than they do within the GUI builder. + +But even more importantly, scrolling behavior and editing is impacted by design choices. E.g. in the video I made the login form scrollable. This isn’t something I thought I needed initially, but as I played with the UI on smaller devices it became apparent that this form must be scrollable. Using cloud connect saved me from the frustration of “compile → deploy → repeat”. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **codelessfuture** — November 20, 2018 at 11:00 am ([permalink](https://www.codenameone.com/blog/introducing-cloud-connect.html#comment-23935)) + +> codelessfuture says: +> +> Have you had some copy & paste problem? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-cloud-connect.html) + + +### **Shai Almog** — November 20, 2018 at 11:02 am ([permalink](https://www.codenameone.com/blog/introducing-cloud-connect.html#comment-24073)) + +> Shai Almog says: +> +> What do you mean? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-cloud-connect.html) + + +### **Shai Almog** — November 20, 2018 at 11:07 am ([permalink](https://www.codenameone.com/blog/introducing-cloud-connect.html#comment-24083)) + +> Shai Almog says: +> +> OK, I see it now. It must have picked a command-c when I was in a different desktop… Will fix this soon. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-cloud-connect.html) + + +### **Boniface N. Githinji** — November 20, 2018 at 11:38 am ([permalink](https://www.codenameone.com/blog/introducing-cloud-connect.html#comment-24103)) + +> Boniface N. Githinji says: +> +> @codenameone:disqus Good job. Without this feature, developing apps on CN1 caused quite the headache especially when one need to see how that 2mm padding looks on the real device. Definitely gonna try it out. +> +> On other news, I am internally grateful to you and your team. I have now built 10+ apps on this great platform and I can attest that there’s nothing as good. Here’s my latest – [https://play.google.com/sto…]() a carpooling app used in Kenya. +> +> [https://uploads.disquscdn.c…]() +> [https://uploads.disquscdn.c…]() [https://uploads.disquscdn.c…]() [https://uploads.disquscdn.c…]() [https://uploads.disquscdn.c…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-cloud-connect.html) + + +### **Shai Almog** — November 21, 2018 at 7:08 am ([permalink](https://www.codenameone.com/blog/introducing-cloud-connect.html#comment-24026)) + +> Shai Almog says: +> +> Looks great! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-cloud-connect.html) + + +### **Chen Fishbein** — November 22, 2018 at 7:19 am ([permalink](https://www.codenameone.com/blog/introducing-cloud-connect.html#comment-24085)) + +> Chen Fishbein says: +> +> Nice job!!! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-cloud-connect.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/introducing-codename-one-7-0-aka-video.md b/docs/website/content/blog/introducing-codename-one-7-0-aka-video.md new file mode 100644 index 0000000000..e5191bacff --- /dev/null +++ b/docs/website/content/blog/introducing-codename-one-7-0-aka-video.md @@ -0,0 +1,156 @@ +--- +title: Introducing Codename One 7.0 (AKA Video) +slug: introducing-codename-one-7-0-aka-video +url: /blog/introducing-codename-one-7-0-aka-video/ +original_url: https://www.codenameone.com/blog/introducing-codename-one-7-0-aka-video.html +aliases: +- /blog/introducing-codename-one-7-0-aka-video.html +date: '2021-02-05' +author: Shai Almog +--- + +![Codename One 7.0 - Video](/blog/introducing-codename-one-7-0-aka-video/7.0-Video-1c.jpg) + +We’re thrilled to announce the immediate availability of Codename One 7.0 (AKA Video). This has been our most challenging release to date. We constantly shifted the release date due to constantly shifting requirements and pivotal changes. + +### Highlights of this Release + +Here are the highlights of Codename One 7.0 + +### WebRTC Support + +This is probably one of the biggest challenges we took to date. We now have one of the best cross platform WebRTC implementations. This took a lot of work and proved to be a huge challenge in every single platform. + +### Build App + +With the new build app we want to change the process of building/working with Codename One. Right now it’s “just” a more unified settings/build experience but we plan to make it central to Codename One development. This will reduce the importance of the IDE plugins and of the build app. + +### CEF Migration + +It’s now possible to use proper web APIs and debug web based code embedded in a Codename One application. This also finally removes the problematic JavaFX dependency we had for our simulator and desktop ports. + +### [CodeRad](https://github.com/shannah/CodeRAD) + +[CodeRAD](https://github.com/shannah/CodeRAD) might end up being the biggest feature of this release. It’s a higher level approach for building Codename One apps that makes building elaborate apps much easier. + +### New Website and SSO + +This isn’t quite a Codename One feature but it’s a huge change to the way we handle builds, signups etc. + +### Other Features + +Those were the highlights but there were also a few important smaller features. There are too many to list but here are some that you might find interesting: + +→ [Sign in with Apple Support](https://www.codenameone.com/blog/sign-in-with-apple-support.html) – this also includes some improvements to the OAuth support + +→ New [KitchenSink](https://play.google.com/store/apps/details?id=com.codename1.demos.kitchen) Demo + +→ [AudioRecorderComponent](https://github.com/codenameone/CodenameOne/commit/cc6ba706e1bd407de0fc9405ce7950d8c4392053) + +→ [API to set video capture constraints](https://github.com/codenameone/CodenameOne/commit/4d605b9ca8f836f7d771ba4eaec9f73e152fc9d5) + +→ Multiple fixes to ParparVM (used in the iOS port) mostly for Kotlin support and wider support of the Java API + +→ [Dark Mode API](/blog/dark-mode.html) + +→ [Sheet Component](https://www.codenameone.com/blog/sheet-positions.html) + +→ [SpanMultiButton Component](https://github.com/codenameone/CodenameOne/commit/b5863f65be564756680a97b1aa90df68a9edfc10) + +→ Improved [CSS Image Border](https://github.com/codenameone/CodenameOne/commit/12ac33405c0db920cf73c0c54a42cb3c6186d080) support + +→ [Tooltips](https://github.com/codenameone/CodenameOne/commit/94610310187ade1bc0a2adbf0850618c15e36515) Support + +→ [Safe download](https://github.com/codenameone/CodenameOne/commit/20dd950faa698bd4722f950763b5e462b5975340) even when minimized + +→ Labels (and their subclasses) now [support badging](https://github.com/codenameone/CodenameOne/commit/4875e5f7b250a9015f16bec2709468bf35f2f129) + +→ Better Java to JavaScript interaction with [postMessage](https://github.com/codenameone/CodenameOne/commit/64d8464109331c00908c2a18123fa21ac2598e09) + +→ [Arrow dialogs](https://github.com/codenameone/CodenameOne/commit/921395f6613e7a2bb883f41d4217797f7d790fa9) now work in a cross platform way + +→ [Radar Chart](https://github.com/codenameone/CodenameOne/commit/675a0ca5018705d5080f1ce393f107a4deedb305) + +→ [Async Media](https://www.codenameone.com/blog/media-async-play-and-pause-support.html) + +### Moving Forward + +Codename One 8 will continue in some of the same directions but will also pivot strongly towards more open architectures. + +We intend to build more upon the basic framework of Codename One Build. We think it’s better to use a single app to manage the build, settings and everything related to Codename One as opposed to using multiple plugins. + +This will let us simplify the plugins and make them easier to update/maintain. + +We also plan to migrate to Maven. This is already in progress and will materialize within the next couple of months. This will simplify some aspects of our build process and update/dependency management. + +We will use CSS as the default framework effectively deprecating the designer approach. While the designer has many advantages ultimately CSS is the de-facto standard and with live CSS editing it’s a pretty compelling case. + +We would also like to strengthen our desktop offering. We believe Codename One on the desktop has a unique value proposition for Java developers that no other framework offers at this time. This is especially true with our CEF support. + +Finally, we intend to make it easier to build Codename One from sources and work with the open source code that’s already available. + +### How Can You Help? + +If you think we are doing a good job and appreciate our help, please help us by: + + +– [Spreading the word](https://www.codenameone.com/blog/how-you-can-help-spread-codenameone.html) + +– [Edit our docs](https://www.codenameone.com/blog/tip-edit-docs-fun-profit.html) + +– [Edit our sources and submit bug fixes](https://www.codenameone.com/blog/how-to-use-the-codename-one-sources.html) + +[– Signup/Upgrade](https://www.codenameone.com/pricing.html) your account + +If your company can afford it, please take the time and upgrade to enterprise, this will allow us to work on the things that are important for your company! + +Thanks for reading this far and if you have any thoughts/suggestions of any kind please let us know! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Javier Anton** — February 6, 2021 at 11:15 pm ([permalink](https://www.codenameone.com/blog/introducing-codename-one-7-0-aka-video.html#comment-24400)) + +> Javier Anton says: +> +> Congratulations and can’t wait to see where CN1 goes from here +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-codename-one-7-0-aka-video.html) + + +### **IMIENS CORP** — February 9, 2021 at 8:26 am ([permalink](https://www.codenameone.com/blog/introducing-codename-one-7-0-aka-video.html#comment-24407)) + +> IMIENS CORP says: +> +> Thank you so much, for adding WebRTC ! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-codename-one-7-0-aka-video.html) + + +### **IMIENS CORP** — February 9, 2021 at 8:33 am ([permalink](https://www.codenameone.com/blog/introducing-codename-one-7-0-aka-video.html#comment-24408)) + +> IMIENS CORP says: +> +> BTW, any examples, docs on WebRTC ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-codename-one-7-0-aka-video.html) + + +### **Shai Almog** — February 10, 2021 at 2:06 am ([permalink](https://www.codenameone.com/blog/introducing-codename-one-7-0-aka-video.html#comment-24409)) + +> Shai Almog says: +> +> Nothing serious yet but initial stuff is in the project page: +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-codename-one-7-0-aka-video.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/introducing-codename-one-maker.md b/docs/website/content/blog/introducing-codename-one-maker.md new file mode 100644 index 0000000000..2548b3a2fd --- /dev/null +++ b/docs/website/content/blog/introducing-codename-one-maker.md @@ -0,0 +1,70 @@ +--- +title: Introducing Codename One Maker +slug: introducing-codename-one-maker +url: /blog/introducing-codename-one-maker/ +original_url: https://www.codenameone.com/blog/introducing-codename-one-maker.html +aliases: +- /blog/introducing-codename-one-maker.html +date: '2013-05-21' +author: Shai Almog +--- + +![Header Image](/blog/introducing-codename-one-maker/hqdefault.jpg) + + + +We are about to release a brand new product: +[ +Maker +](/maker.html) +. Codename One Maker is an App that allows non-developers to build native applications directly from their mobile phone or tablet by using the Codename One backend. + +The tool is relatively simple and produces “cookie cutter” applications, however we think that you would be able to build amazing plugins to make the tool truly powerful + +. We intend to introduce a plugin architecture based on our Codename One libraries that will allow you to build extensions to Maker using our standard Java API and native code. + + +For now Maker contains an option to get the Codename One source code upon build completion which will allow novices to prototype the applications they want then give a developer the source code in order to get the professional features into place. Let us know what you think in the comments below. + + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — May 23, 2013 at 5:20 am ([permalink](https://www.codenameone.com/blog/introducing-codename-one-maker.html#comment-21626)) + +> Anonymous says: +> +> This is great news, I know so many people will have a good opportunity to air their opinions via ‘mobile development’ good work team Codename One… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-codename-one-maker.html) + + +### **Anonymous** — May 23, 2013 at 1:01 pm ([permalink](https://www.codenameone.com/blog/introducing-codename-one-maker.html#comment-21768)) + +> Anonymous says: +> +> Great, I travel a lot and I’ll be able to prototype from my tablet, then code on eclipse. Also my business partner who dont program will be able to prototype =) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-codename-one-maker.html) + + +### **Anonymous** — May 24, 2013 at 3:32 am ([permalink](https://www.codenameone.com/blog/introducing-codename-one-maker.html#comment-24231)) + +> Anonymous says: +> +> thats so cool…. i think this is a huge step… the revolution to mobile and more so android programming +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-codename-one-maker.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/introducing-codename-one-websocket-support.md b/docs/website/content/blog/introducing-codename-one-websocket-support.md new file mode 100644 index 0000000000..c6efd5741f --- /dev/null +++ b/docs/website/content/blog/introducing-codename-one-websocket-support.md @@ -0,0 +1,159 @@ +--- +title: Introducing Codename One WebSocket Support +slug: introducing-codename-one-websocket-support +url: /blog/introducing-codename-one-websocket-support/ +original_url: https://www.codenameone.com/blog/introducing-codename-one-websocket-support.html +aliases: +- /blog/introducing-codename-one-websocket-support.html +date: '2015-08-09' +author: Steve Hannah +--- + +![Header Image](/blog/introducing-codename-one-websocket-support/html5-banner.jpg) + +Codename One already has two separate socket APIs: [a low-level API](https://github.com/shannah/CN1Sockets) similar to `java.net.Socket` and [a higher-level event-based approach](http://www.codenameone.com/blog/sockets-multiline-trees.html). So why do we need WebSockets? + +Here are 3 reasons: + +### 1\. Simplifies Server Code + +With low-level TCP sockets, you can’t just add a servlet to your existing Java web app to handle socket connections. You have to create your own server, and have it listen for connections on some custom port. You have to create your own sort of protocol. And all this just so you can pass messages. + +With Web Sockets, you simply add an end point to your Java web app, and implement a few callbacks (e.g. `onMessage()`, `onOpen()`, `onClose()`, `onError()`), and you’re good to go. + +E.g. Here is the full code for server-side of the [chat app demo](https://github.com/shannah/cn1-websockets#chat-demo): + + + @ServerEndpoint("/chat") + public class ChatDemoEndpoint { + + + private static Set peers = Collections.synchronizedSet(new HashSet()); + @OnMessage + public String onMessage(Session session, String message) { + System.out.println(session.getUserProperties()); + if (!session.getUserProperties().containsKey("name")) { + session.getUserProperties().put("name", message); + return null; + } + for (Session peer: peers) { + try { + peer.getBasicRemote().sendText(session.getUserProperties().get("name")+": "+message); + } catch (IOException ex) { + Logger.getLogger(ChatDemoEndpoint.class.getName()).log(Level.SEVERE, null, ex); + } + } + return null; + } + + @OnOpen + public void onOpen(Session peer) { + peers.add(peer); + } + + @OnClose + public void onClose(Session peer) { + peers.remove(peer); + } + + } + +The server just keeps a list of the open sessions, then it distributes messages received from any session to all sessions. Simple. + +### 2\. Simplifies Client Code + +Codename One’s existing high-level sockets API, being event-based, already takes some of the nasties out of socket programming. But Web sockets are still simpler. The symmetry between the client and server APIs makes for a pleasant experience. Just implement the same callbacks in the client, and you’re in business. Passing messages between server and clients couldn’t be simpler. + +E.g. Here is the companion client code for the [chat app demo](https://github.com/shannah/cn1-websockets#chat-demo): + + + sock = new WebSocket(SERVER_URL) { + + @Override + protected void onOpen() { + System.out.println("In onOpen"); + } + + @Override + protected void onClose(int statusCode, String reason) { + + } + + @Override + protected void onMessage(final String message) { + System.out.println("Received message "+message); + Display.getInstance().callSerially(new Runnable() { + + public void run() { + if (chatContainer == null) { + return; + } + SpanLabel label = new SpanLabel(); + label.setText(message); + chatContainer.addComponent(label); + chatContainer.animateHierarchy(100); + } + + }); + } + + @Override + protected void onError(Exception ex) { + System.out.println("in onError"); + } + + @Override + protected void onMessage(byte[] message) { + + } + + }; + System.out.println("Sending connect"); + sock.connect(); + +This connects to the server using a url (just like any GET or POST request), then listens for messages from the server in the `onMessage()` method. + +### 3\. Easier to Implement Cross-Platform + +Implementing low-level TCP sockets in the [Javascript port](http://www.codenameone.com/blog/javascript-port.html) looked like it would be challenging, at best, and possibly impossible. But I wanted to be able to write cross-platform apps in Codename One that use sockets – and I wanted to be able to deploy to the Javascript port. Since WebSockets are a first-class citizen in the web, adding support to the Javascript port was trivial. + +Since the websocket standard is now widely established and supported, it should be fairly easy to implement on other platforms as well. So far, I’ve implemented JavaSE, Android, iOS, and Javascript. Notably I’m missing Windows Phone, but it shouldn’t be hard to implement if a WinPhone developer wants to take on the challenge. + +## Integrating WebSockets in your Project + +Check out the [cn1-websockets project](https://github.com/shannah/cn1-websockets) for more information +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — December 19, 2017 at 12:33 pm ([permalink](https://www.codenameone.com/blog/introducing-codename-one-websocket-support.html#comment-23794)) + +> Francesco Galgani says: +> +> I’m starting to search information on Codename One WebSockets because this discussion: +> [https://stackoverflow.com/q…]() +> I didn’t find information on WebSockets in the developer guide, but I found this page. Please note that the following page gives a 404 error: [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-codename-one-websocket-support.html) + + +### **Shai Almog** — December 20, 2017 at 6:33 am ([permalink](https://www.codenameone.com/blog/introducing-codename-one-websocket-support.html#comment-23647)) + +> Shai Almog says: +> +> Thanks, I’ll remove that tag. +> +> WebSockets is an external cn1lib so it’s not in the developer guide. I hope to add a chapter covering important cn1libs such as websockets, google maps etc. at some point in the future. Currently the best up to date docs for websocket support are here: [https://github.com/shannah/…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fintroducing-codename-one-websocket-support.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/introduction-to-uifragment.md b/docs/website/content/blog/introduction-to-uifragment.md new file mode 100644 index 0000000000..caef7c4d2d --- /dev/null +++ b/docs/website/content/blog/introduction-to-uifragment.md @@ -0,0 +1,413 @@ +--- +title: Introduction to UIFragment +slug: introduction-to-uifragment +url: /blog/introduction-to-uifragment/ +original_url: https://www.codenameone.com/blog/introduction-to-uifragment.html +aliases: +- /blog/introduction-to-uifragment.html +date: '2019-03-18' +author: Steve Hannah +--- + +![Header Image](/blog/introduction-to-uifragment/uidesign.jpg) + +I recently became frustrated by the amount of work I had to put into recreating a Component hierarchy programmatically. For a test case, I needed to create a Form with a text field in the bottom, and a button just above it on the right. + +I ended up with code that looked like: + + + Form f = new Form("Test Form", new BorderLayout()); + + Container south = new Container(new BorderLayout()); + south.add(BorderLayout.SOUTH, new TextField()); + south.add(BorderLayout.NORTH, FlowLayout.encloseRight(new Button("Submit"))); + + f.add(BorderLayout.SOUTH, south); + + f.show(); + +The result looks something like: + +![Image 110319 095240.611](/blog/introduction-to-uifragment/Image-110319-095240.611.png) + +This isn’t all that bad, but it feels like it could be made simpler. It isn’t entirely obvious what the finished result will look like by looking at the Java code. This is largely due to the imperative notation. A declarative notation would be easier to read. + +Codename One uses XML, a declarative language, as the underlying format for its GUI builder but this isn’t designed to be written or read by a human. It would be nice if I could express this UI using a notation that is both optimally succinct, and easy to read. + +So, I created such a notation, and wrapped it in a class named `UIFragment`. + +### A New Declarative UI Notation + +UIFragment supports both an XML and a JSON notation. Both are compiled down to the same underlying structure, which is based on the XML notation. I.e. If you use the JSON notation, it will just be converted to the XML version under the hood. + +Let’s take a look at the above example, using XML: + + + + + <$myTextField constraint="south"/> + + <$submitButton/> + + + + +This XML can be transformed into a `Component` using + + + Component cmp = UIFragment.parseXML(xmlString) + .set("myTextField", new TextField()) + .set("submitButton", new Button("Submit")) + .getView(); + +While this notation is slightly easier to read than it’s pure-java equivalent, it is still quite lengthy. For a UI like this, I’d like a notation that I can easily stick into a single-line +string. So let’s take a look at the JSON-ish UI notation. + + + {south:{north:{flow:[$myTextField], align:right}, south:$submitButton}} + +And this can be further shorthened using the single-character layout constraint aliases to: + + + {s:{n:{flow:[$myTextField], align:right}, s:$submitButton}} + +Notice that this JSON is not quite valid JSON. The property keys aren’t quoted, and neither are some of the values. This is OK, as the JSON parser for `UIFragment` is using non-strict mode, so as to eliminate all extra syntax that would only make our notation more difficult to write. + +Using JSON, the entire Java source for the above example becomes: + + + Form f = new Form("Test Form", new BorderLayout()); + f.add( + BorderLayout.CENTER, + UIFragment.parseJSON("{s:{n:{flow:[$myTextField], align:right}, s:$submitButton}}") + .set("myTextField", new TextField()) + .set("submitButton", new Button("Submit")) + .getView() + ); + f.show(); + +While the total lines of code hasn’t changed, the portion related to constructing the UI is certainly shorter, and it is now easy to understand what the structure will be. + +## Syntax + +The syntax is built around containers. Rather that have a `container` tag, I opted to use a separate tag for each layout type. This makes the syntax both easier to read and easier to write. Instead of `` we simply have ``. + +The supported layouts are shown in the following table. + +Table 1. Container notation Layout | XML | JSON +---|---|--- +TableLayout | `…​…​
…​
` | `{table:[[],…​]}` +BorderLayout | `…​` | `{c:[], n:[], e:[], w:[], s:[], o:[]}` +FlowLayout | `…​` | `{flow:[], align:center, valign:top}` +BoxLayout X | `…​` | `{x:[]}` +BoxLayout Y | `…​` | `{y:[]}` +GridLayout | `…​` | `{grid:[], rows:3, cols:2}` +LayeredLayout | `…​` | `{layered:[]}` + +### Placeholders + +Rather than creating tags for every Component type, I chose to leave it simple. Only Containers can be expressed using the XML/JSON notation. Components should be represented using placeholders, and a corresponding call to `set(String,Component)` must be made on the UIFragment to bind a Component to the placeholder. + +E.g. + + + UIFragment.parseJSON("{s:$myButton}") + .set("myButton", new Button("Hello")) + +The above example creates a Container with a button placed in its south position. The `$myButton` placeholder will be replaced by the button that we passed to `set()`. Notice that the placeholder is prefixed with a `$`. + +The XML equivalent of the above is: + + + UIFragment.parseXML("<$myButton constraint='south'/>") + .set("myButton", new Button("Hello")) + +### Attributes + +There are a small number of attributes which can be added to elements of a UIFragment. These include: + + * `uiid` – The UIID to set on the element. + + * `id` – An ID that can be used to obtain a direct reference to the Container via the `UIFragment.findById(String)` method. This is useful if you need to provide further customizations on the Container in Java that aren’t possible using XML or JSON. + + * `class` – This works like the HTML `class` attribute works. It assigns `tags` to the container that can be used by `ComponentSelector` to select the resulting component. Multiple tags are separated by spaces. + +There are also some attributes that are only applicable to certain container types. E.g. `` supports `align` and `valign` attributes which accept “left”, “right”, “center”, and “top”, “bottom”, “center” respectively for values. + +`` and `` both support `rows` and `cols` attributes which specify the number of rows and columns in their layouts respectively. On `
` these are optional attributes. If they are omitted it will use the actual data in the table to figure out the correct number of rows and columns. + +### Labels + +Labels are a special case which are supported in UIFragments without having to use a placeholder. The XML notation supports a `
"+ + ""+ + "
<$name/>
<$age/>
<$active/>
") + .set("name", new TextField()) + .set("age", new TextField()) + .set("active", new CheckBox()) + .getView(); + +The result is: + +![Image 110319 114149.837](/blog/introduction-to-uifragment/Image-110319-114149.837.png) + +### Reusing a Fragment + +Suppose you have a UIFragment that defines a single row of a list. When this list grows to hundreds or thousands of rows, it may become expensive to re-parse the JSON or XML for each row fragment. Luckily, you don’t need to do that. You can create the fragment once, and then use it to generate a different view for each row. + +Consider this example using the Contacts API. + + + Contact[] contacts = Display.getInstance().getAllContacts(true, true, true, true, true, true); + UIFragment fragment = UIFragment.parseJSON("{w:$icon, c:{n:$name, s:[$phone, '/', $email]}}"); + Container cnt = new Container(BoxLayout.y()); + for (Contact contact : contacts) { + Component row = fragment.set("icon", (contact.getPhoto() == null) ? + new Button(FontImage.MATERIAL_ADD_A_PHOTO) : new Button(contact.getPhoto().scaledHeight(20))) + .set("name", new Label(contact.getDisplayName())) + .set("phone", new Label(contact.getPrimaryPhoneNumber())) + .set("email", new Label(contact.getPrimaryEmail())) + .getView(); + $(row).selectAllStyles().setBorder(Border.createUnderlineBorder(1)) + .setBgColor(0xffffff) + .setBgTransparency(0xff); + cnt.add(row); + } + + f.add(BorderLayout.CENTER, cnt); + +In this example, we parse the JSON only once, when `UIFragment.parseJSON()` is called. Then we iterate through each contact, setting the placeholders for each row. This works because once `getView()` has been called, the next subsequent call to `set()` will result in the fragment’s `view’ getting reset. This works similar to the way a prepared database query works in JDBC. The query is compiled (prepared) once, and changing the placeholders results in a different effective query. + +And the result: + +![Image 110319 120333.100](/blog/introduction-to-uifragment/Image-110319-120333.100.png) + +### Accessing Components in the Fragment + +The JSON and XML notations offer only a limited amount of customization options for elements. The `uiid` attribute allows you to set the UIID for a component, but that’s about it. If you want to customize it further, you’ll need to obtain a reference to the actual component, and customize it directly using its Java API. There are two ways to obtain references to the components in a fragment. + + 1. Add the `id` attribute to the component, then use the `findById()` method of the fragment to access it. + + 2. Add the `class` attribute to the component to add “tags” that can be selected by the ComponentSelector class. + +Example using `findById()` + + + UIFragment fragment = UIFragment.parseJSON("{c:{flow:'Hello World', id:'MyContainer'}}"); + Container myContainer = (Container)fragment.findById("MyContainer"); + $(myContainer).setPaddingMillimeters(10); + Container cnt = fragment.getView(); + +In the above example we set the ‘id’ attribute on the nested FlowLayout Container, so that we can fetch it via `findById()`. Then we set the padding on that container using the Java API. The result: + +![Image 110319 123838.820](/blog/introduction-to-uifragment/Image-110319-123838.820.png) + +Example using `class` Attribute and ComponentSelector + + + Container view = UIFragment.parseJSON("{c:{flow:'Hello World', class:'tag1 tag2'}, s:{flow:'South', class:'tag2'}") + .getView(); + $(".tag1", view).selectAllStyles().setBgColor(0xff0000).setBgTransparency(0xff); + $(".tag2", view).selectAllStyles().setBorder(Border.createLineBorder(1)); + +This example demonstrates the use of the `class` attribute for setting tags that can be used by `ComponentSelector` for selecting nested components in the fragment. We have two nested containers. One in the center with tags “tag1” and “tag2”; and a second component in the south with tag “tag2” only. + +We’re able to select on “tag1” to set the background color of the first component to red. Then we selet on “tag2” (which selects both of the components), to set the border of both components to use a line border. + +The result: + +![Image 110319 124528.887](/blog/introduction-to-uifragment/Image-110319-124528.887.png) + +## Summary + +`UIFragment` provides simple way to user interfaces using a declarative syntax. It supports both an XML and a JSON syntax. The JSON notation is almost always more succinct and easier to read than the XML equivalent, and both provide advantages over directly defining the UI in Java code. You can embed placeholders inside your fragment’s JSON/XML and have them replaced by custom components when the fragment is compiled. Additionally, you can access nested components within fragments for further customization by tagging them either with an “id” or a “class” attribute. Finally you can reuse the same fragment to generate entire sets of components by setting placeholders with different values. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/invite-friends-websockets-windows-phone-more.md b/docs/website/content/blog/invite-friends-websockets-windows-phone-more.md new file mode 100644 index 0000000000..1ffe536489 --- /dev/null +++ b/docs/website/content/blog/invite-friends-websockets-windows-phone-more.md @@ -0,0 +1,192 @@ +--- +title: Invite Friends, WebSockets, Windows Phone & More +slug: invite-friends-websockets-windows-phone-more +url: /blog/invite-friends-websockets-windows-phone-more/ +original_url: https://www.codenameone.com/blog/invite-friends-websockets-windows-phone-more.html +aliases: +- /blog/invite-friends-websockets-windows-phone-more.html +date: '2015-08-02' +author: Shai Almog +--- + +![Header Image](/blog/invite-friends-websockets-windows-phone-more/facebook-invite-friends.jpg) + +We’ve released a burst of small new features that piled up during the code freeze and release cycle, we also have a couple of interesting +3rd party efforts such as an independent Windows Phone port and websockets implementation. But first lets start with +Facebooks “invite friends” feature. Historically with the Facebook API you could just use the Graph API to query +Facebook for the list of friends. This will return an empty list now and will only expose friends who are already using the +app. You can use the standard share button or Facebook share both of which are great options to promote your app. +However, Facebook also has a special native API allowing the user to invite his friends into the app… + +The `FacebookConnection` class now has support for that feature, its a non-trivial feature and you will need to activate +some options within the Facebook application in order to fully utilize it but its a pretty powerful feature if you use +Facebook login and want to promote your app socially. + +#### Windows Phone Port + +As you may recall, we are taking a [“wait and see” +approach for the future of the Windows Phone port](/blog/login-tutorials-future-of-windows-phone.html) based on MS’s historical flakyness when committing to +technologies. However, some developers need to release a version to Windows Phone now and Fabricio who is one such developer +took it upon himself to improve the current port with some interesting results. You can check out his companies project +[here](https://github.com/Pmovil/CN1WindowsPort). + +There are several inherent problems that would be harder still to fix, they derive from the C# based port that relies on +XMLVM. Since XMLVM was effectively discontinued and its C# backend was experimental at best it contains a +lot of bugs that you might need to workaround. The proper solution would be to port the new VM built for iOS +to Windows Phone, it was designed to be very portable so this should be relatively easy. It should also provide a +nice performance boost, C# is pretty fast but the XMLVM layer on top isn’t as efficient as it should be due to language +inconsistencies between C# and Java. + +If you would like us to put more effort into Windows Phone support please signup as an enterprise account and +make your voice heard. + +#### Websocket cn1lib & Chat + +[Steve](http://sjhannah.com/) already released a +[sockets cn1lib](https://github.com/shannah/CN1Sockets) a while back and +he just introduced a [new websocket cn1lib](https://github.com/shannah/cn1-websockets) +yesterday! + +The websockets standard is designed to provide the web generation of tools with the power/speed of socket +communication without getting into some of the low level oddities of the TCP protocol. The really nice thing +about websockets, is that you can just program to it using a webserver with URL based notations which simplifies +a lot of the hassle you might have normally with socket programming. + +As part of the release [Steve](http://sjhannah.com/) also added a chat app that +communicates between users. Its a really interesting approach and you might find it very useful if you want to +integrate chat functionality in your application. + +#### URLImage.createMaskAdapter + +Up until now the `URLImage` class only supported relatively simple adapters out of the box, +specifically scaling of various types. We now have a new API called `URLImage.createMaskAdapter` +that accepts a mask image. You can then apply this adapter to the `URLImage` creation and thus +apply a mask to the stored image. E.g. we use it in the chat app demo to create a circular image of the speaker. + +#### Util Methods + +One of the most annoying pieces of code I write all the time is: + + + try { + Thread.sleep(ms); + } catch(InterruptedException e) {} + +I love checked exceptions but they are problematic when they are misused in cases where they make no sense at +all (e.g. threads are never interrupted on iOS). So to reduce this pain we added two methods to `Util`: +`sleep(int)` and `wait(Object, int)`. +They do pretty much what you expect and don’t throw an exception with the added bonus in the case of wait where +it implicitly declares the `synchronized` block for you removing the need for you to do that so you can +convert this: + + + try { + syncronized(obj) { + obj.wait(ms); + } + } catch(InterruptedException e) {} + +To: + + + Util.wait(obj, ms); + +#### Simplified Theme Initialization + +Up until now handcoded Codename One apps had a pretty standard set of boilerplate code: + + + try { + theme = Resources.openLayered("/theme"); + UIManager.getInstance().setThemeProps(theme.getTheme(theme.getThemeResourceNames()[0])); + } catch(IOException e){ + e.printStackTrace(); + } + +Its redundant since its rarely changed by users and when it is changed its usually with one purpose (setting +a specific theme). So rather than write all that code we now use: + + + theme = UIManager.initFirstTheme("/theme"); + +Which is exactly the same block of code wrapped in a method. +If you want to explicitly specify the theme you can use + + + theme = UIManager.initNamedTheme("/theme", "MyTheme"); + +Which is still more concise and ignores the `IOException` which can’t be handled properly this +early in the app anyway. + +#### CaseInsensitiveOrder + +The `String` class in Java SE has a member comparator called `String.CASE_INSENSITIVE_ORDER` +and that’s really useful when we want to do something like: + + + ContactData[] cnts = data.getContacts(); + Arrays.sort(cnts, (ContactData o1, ContactData o2) -> { + return String.CASE_INSENSITIVE_ORDER.compare(o1.name, o2.name); + }); + +Which allows us to effectively sort an array or collection based on a string element very easily. However, having this +in the `String` class is painful when we have to do it to multiple platforms. Furthermore this approach is +inefficient since the object needs to be instantiated even when its unused so we’d rather not add something like +that to a mobile device platform where every KB counts. +As a result we decided to add the class `CaseInsensitiveOrder` which is effectively almost identical: + + + ContactData[] cnts = data.getContacts(); + CaseInsensitiveOrder co = new CaseInsensitiveOrder(); + Arrays.sort(cnts, (ContactData o1, ContactData o2) -> { + return co.compare(o1.name, o2.name); + }); +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Fabrício Cabeça** — August 3, 2015 at 4:52 pm ([permalink](https://www.codenameone.com/blog/invite-friends-websockets-windows-phone-more.html#comment-22297)) + +> Fabrício Cabeça says: +> +> Hi Shai, thanks for mentioning our efforts with the Windows port, we are working hard to make it fast, stable and feature complete. We do have an internal schedule for features like in-app purchase and facebook native integration and we plan to release some of our apps using this port in the near future. Any pro/enterprise user willing to help would be most welcome. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finvite-friends-websockets-windows-phone-more.html) + + +### **ftp27** — August 4, 2015 at 11:25 am ([permalink](https://www.codenameone.com/blog/invite-friends-websockets-windows-phone-more.html#comment-22375)) + +> ftp27 says: +> +> Thanks for WebSockets plugin! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finvite-friends-websockets-windows-phone-more.html) + + +### **shannah78** — August 4, 2015 at 4:38 pm ([permalink](https://www.codenameone.com/blog/invite-friends-websockets-windows-phone-more.html#comment-22305)) + +> shannah78 says: +> +> Your welcome 🙂 Your original comment mentioned that you were having trouble on iOS. Did you solve this? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finvite-friends-websockets-windows-phone-more.html) + + +### **ftp27** — August 5, 2015 at 8:17 am ([permalink](https://www.codenameone.com/blog/invite-friends-websockets-windows-phone-more.html#comment-21544)) + +> ftp27 says: +> +> Yes. This trouble has been associated with animate function in iOS. I replace this function to revalidate and all began worked fine. This was not associated with WebSockets. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finvite-friends-websockets-windows-phone-more.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/invoke-without-blocking.md b/docs/website/content/blog/invoke-without-blocking.md new file mode 100644 index 0000000000..da77cff2a4 --- /dev/null +++ b/docs/website/content/blog/invoke-without-blocking.md @@ -0,0 +1,165 @@ +--- +title: When You Cannot Afford to Block the EDT +slug: invoke-without-blocking +url: /blog/invoke-without-blocking/ +original_url: https://www.codenameone.com/blog/invoke-without-blocking.html +aliases: +- /blog/invoke-without-blocking.html +date: '2019-11-28' +author: Steve Hannah +--- + +![Header Image](/blog/invoke-without-blocking/new-features-3.jpg) + +We recently added support for disabling `invokeAndBlock()` for certain sections of code. The syntax is: + + + CN.invokeWithoutBlocking(()->{ + // This code is not allowed to call invokeAndBlock() + }); + +If any attempt is made to execute `invokeAndBlock()` inside that block of code, it will throw a `BlockingDisallowedException`. + +This can be useful for ensuring that your UI will be responsive, especially in cases where you’re building a new form to show to the user, and any delay will be noticed by the user. + +For example: + + + Button btn = new Button("Show Details"); + btn.addActionListener(evt->{ + DetailsForm form = new DetailsForm(); + form.show(); + }); + +The intention is that the user presses the “Show Details” button, and they are shown some sort of details form. But what if, somewhere in the construction of the `DetailsForm`, there is a call to `invokeAndBlock()`? A common reason for this is if a network call is performed during the building of the form. For example: + + + DetailsModel model = loadDetailsFromServer(); // A synchronous call to the server + nameField.setText(model.getName()); + ... + +That `loadDetailsFromTheServer()` is a synchronous call to the server, so it uses `invokeAndBlock()` to be able to “block” control flow without actually blocking the EDT. It’s great that it doesn’t block the EDT, but it still blocks our ability to deliver the details form that the user is expecting. The form won’t be built until after the network request complete, then the user will experience a short delay before transitioning to the new form. + +A better way is to build and show the `DetailsForm`, perform an asynchronous network request, and then update the details form with the data received when the network request completes. E.g. + + + loadDetailsFromServerAsync().ready(model->{ + nameField.setText(model.getName()); + revalidateWithAnimationSafety(); + }); + +An easy fix in this simple case. But in the real world apps are much more complex. Calls to `invokeAndBlock()` may be nested deep within your app, or its libraries, so it may not be easy to ensure that the `DetailsForm` can be created without blocking. + +This is where `invokeWithoutBlocking()` comes in handy. Let’s wrap our form creation to make sure that it doesn’t get bogged down by a slow network request. + + + Button btn = new Button("Show Details"); + btn.addActionListener(evt->{ + CN.invokeWithoutBlocking(()->{ + DetailsForm form = new DetailsForm(); + form.show(); + }); + }); + +This is guaranteed to show the form instantly, or it will throw a `BlockingDisallowedException`. This may be useful, especially during development, to help you hunt down those pesky network requests to get them out of your way. You can also catch these exceptions in order to provide an alternate path in the case that you can’t build the form without blocking. + + + Button btn = new Button("Show Details"); + btn.addActionListener(evt->{ + try { + CN.invokeWithoutBlocking(()->{ + DetailsForm form = new DetailsForm(); + form.show(); + }); + } catch (BlockingDisallowedException ex) { + + showAlternateForm(); + } + }); + +### Background: When to Block the EDT + +Synchronous programming is easier to write and understand than asynchronous programming. You can follow the flow of the code line by line, knowing that line n is run after line n-1, and before line n+1. The problem with synchronous programming is that it causes problems for long-running tasks on threads that can never block. Threads like the event dispatch thread (EDT), which is where most application code runs since it is the only thread that is authorized to interact with the UI. Codename One’s `invokeAndBlock()` method is a nifty tool which allows you to “block” the current event dispatch, without blocking any other event dispatches. Other events and callSerially blocks will continue to be processed while this event is blocked. + +This allows us to do cool things like: + + + MyData data = loadSomeDataFromTheServer(); + updateUIWithMyData(data); + +This can be run directly on the EDT without blocking it because events will continue to be delivered and processed while the single event dispatch that is running this code is waiting for the data to be retrieved from the server. In most cases, this is much more elegant than callbacks, promises, or workers. It is easier to write, and easier to understand. + +However, there is a cost to using `invokeAndBlock()`. It still blocks the current dispatch, which can be problematic in certain contexts. E.g. What if we block the pointer-press dispatch. This might cause components to receive the corresponding pointer-release before the pointer-press – which is counter-intuitive. + +I generally try to avoid using `invokeAndBlock()` directly inside event handlers like action events or pointer events, because you could be getting in the way of other event handlers that are relying on the order events. E.g., Instead of: + + + button.addActionListener(evt->{ + doSomethingWithBlockingCode(); + }); + +Prefer: + + + button.addActionListener(evt->{ + CN.callSerially(evt->{ + doSomethingWithBlockingCode(); + }); + }); + +This way it will only block the contents of that particular callSerially() dispatch. The action event dispatch (which is probably running inside a pointer pressed or pointer release dispatch) can continue to be delivered to other listeners unimpeded. + +I also try to avoid blocking while constructing user interface components to show the user. Usually when I create a form, I want to create it **now** to show the user instantly. + +You can also use callSerially() in this case to prevent the blocking. + +E.g. + + + class MyForm extends Form { + + public MyForm() { + ... + myLabel.setText("Some placeholder"); + callSerially(()->{ + MyData data = loadMyDataFromServer(); + myLabel.setText(data.getSomeString()); + revalidateWithAnimationSafefy(); + } + } + } + +### Conclusion + +`invokeAndBlock()` is a great tool for simplifying control flow, but in some circumstances, using it can negatively impact the user experience. Two places where `invokeAndBlock()` should be avoided is during the construction of UI forms to display to the user, and directly inside an event handler. In some cases you can mitigate the cost of `invokeAndBlock()` by simply wrapping it in a `callSerially()` (e.g. inside an event handler) so that it doesn’t block the current event. When constructing a UI component like a form, you can use `invokeWithoutBlocking()` to provide guarantees that your code doesn’t block, and be sure that the user will be shown your form without delay. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Durank** — December 4, 2019 at 8:52 pm ([permalink](https://www.codenameone.com/blog/invoke-without-blocking.html#comment-24275)) + +> [Durank](https://avatars0.githubusercontent.com/u/16245755?v=4) says: +> +> can I used this code to avoid stopping my infinite rotating image animation while I paint others components in the screen? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finvoke-without-blocking.html) + + +### **Steve Hannah** — December 5, 2019 at 6:37 pm ([permalink](https://www.codenameone.com/blog/invoke-without-blocking.html#comment-24274)) + +> [Steve Hannah](https://lh3.googleusercontent.com/a-/AAuE7mBmUCgKSZtJ2cqeHgj6bdPY2AAQ10roHlMpgRWc) says: +> +> Are you referring to the InfiniteProgress.showInfiniteBlocking() method, or your own custom animation that you’ve made? In either case it probably wouldn’t be affected by this. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Finvoke-without-blocking.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/ios-7-support.md b/docs/website/content/blog/ios-7-support.md new file mode 100644 index 0000000000..477fcbdd23 --- /dev/null +++ b/docs/website/content/blog/ios-7-support.md @@ -0,0 +1,89 @@ +--- +title: iOS 7 Support +slug: ios-7-support +url: /blog/ios-7-support/ +original_url: https://www.codenameone.com/blog/ios-7-support.html +aliases: +- /blog/ios-7-support.html +date: '2013-06-11' +author: Shai Almog +--- + +![Header Image](/blog/ios-7-support/ios-7-support-1.png) + + + + +[ +![Picture](/blog/ios-7-support/ios-7-support-1.png) +](/img/blog/old_posts/ios-7-support-large-2.png) + + + +Apple just announced iOS 7 support the other day and it includes quite a few UI changes. We are already working full speed at incorporating support for iOS 7 before the general availability of the OS and have already released an initial skin through the OTA download feature (it will only work properly with the next plugin update). + + +The trend towards simpler flat design is great since we can now create applications that look good/consistent on all platforms much more easily than we could in the past and we will probably update our themes to incorporate more of the flat design concepts as we move forward. + + +Keep in mind when going over the theme that this is work in progress and that at the moment this isn’t applied to the actual device builds, however when the time comes all you will need to do in order to support the feel of iOS 7 would be to send a build to the build server. + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — January 2, 2014 at 7:42 pm ([permalink](https://www.codenameone.com/blog/ios-7-support.html#comment-21813)) + +> Anonymous says: +> +> Hi CN1, +> +> that sounds great! Is there any ETA on the iOS7 skin? +> +> Thanks, +> +> Emil +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-7-support.html) + + +### **Anonymous** — January 3, 2014 at 3:23 am ([permalink](https://www.codenameone.com/blog/ios-7-support.html#comment-21778)) + +> Anonymous says: +> +> Its been there for a while. Just click the More… option in the skins menu. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-7-support.html) + + +### **Anonymous** — January 3, 2014 at 4:02 am ([permalink](https://www.codenameone.com/blog/ios-7-support.html#comment-21809)) + +> Anonymous says: +> +> I am aware that the skin is available in the simulator. I was referring to the device still using the old skin; sorry for being unclear 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-7-support.html) + + +### **Anonymous** — January 4, 2014 at 6:09 am ([permalink](https://www.codenameone.com/blog/ios-7-support.html#comment-21795)) + +> Anonymous says: +> +> You need to define the build argument ios.themeMode to modern or just wait a couple of weeks till we flip the switch to make iOS 7 the default. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-7-support.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/ios-8-installs-customizing-the-pull-to-refresh.md b/docs/website/content/blog/ios-8-installs-customizing-the-pull-to-refresh.md new file mode 100644 index 0000000000..d40df697fd --- /dev/null +++ b/docs/website/content/blog/ios-8-installs-customizing-the-pull-to-refresh.md @@ -0,0 +1,100 @@ +--- +title: IOS 8 Installs & Customizing the Pull To Refresh +slug: ios-8-installs-customizing-the-pull-to-refresh +url: /blog/ios-8-installs-customizing-the-pull-to-refresh/ +original_url: https://www.codenameone.com/blog/ios-8-installs-customizing-the-pull-to-refresh.html +aliases: +- /blog/ios-8-installs-customizing-the-pull-to-refresh.html +date: '2014-09-21' +author: Shai Almog +--- + +![Header Image](/blog/ios-8-installs-customizing-the-pull-to-refresh/ios-8-installs-customizing-the-pull-to-refresh-1.jpg) + + + + + +![Picture](/blog/ios-8-installs-customizing-the-pull-to-refresh/ios-8-installs-customizing-the-pull-to-refresh-1.jpg) + + + + +One of our pro users alerted us to an issue with iOS 8 that might trigger a case where apps can’t be installed OTA (Over the air, via QR or email links) and only installed via itunes. We didn’t experience this issue ourselves but it seems to be affecting many developers (not Codename One specific). This is due to caching of package bundle ID’s and he provided some resources here that might be of interest: + +[ +https://buildozer.io/ios8 +](https://buildozer.io/ios8) + +[ +http://stackoverflow.com/questions/25887805/ios-8-gm-cant-install-ipa +](http://stackoverflow.com/questions/25887805/ios-8-gm-cant-install-ipa) + +[ +http://stackoverflow.com/questions/25772664/enterprise-app-update-distribution-on-ios-8 +](http://stackoverflow.com/questions/25772664/enterprise-app-update-distribution-on-ios-8) + +[ +http://support.hockeyapp.net/discussions/problems/26683-not-able-to-download-apps-ios8-beta-5-autoupdate-manually-etc#comment_34327687 +](http://support.hockeyapp.net/discussions/problems/26683-not-able-to-download-apps-ios8-beta-5-autoupdate-manually-etc#comment_34327687) + + + + + +On an unrelated subject the +[ +pull to refresh +](http://www.codenameone.com/blog/pull-to-refresh-several-new-how-do-i-videos) +functionality was a bit uncustomizable up until now, this all changed with the latest release and should now be far more customizable. To replace the icon you can define the theme constant pullToRefreshImage to the right image. To customize the appearance of the text etc. you can now use the PullToRefresh UIID and to customize the text just define the following constants in the localization bundle: + + +pull.release (defaults to “Release to refresh…”) & pull.down (defaults to “Pull down do refresh…”). + + + + + +As you may have noticed we are deep into the last minute JavaOne preparations so everything we do is around that work. During the weekend of Friday the 26th both Chen and myself will be in transit to San Francisco and so we will not be able to address support queries or answer forum questions during that time. During that entire week we will have relatively limited forum presence due to our workload at that time. + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — October 7, 2014 at 7:02 pm ([permalink](https://www.codenameone.com/blog/ios-8-installs-customizing-the-pull-to-refresh.html#comment-22041)) + +> Anonymous says: +> +> The solution to the iOS8 issue seems to be to put some random characters into the bundle ID of the plist file. As this is managed by CN1 can you enable this at your end? Its affecting me for my installs as I usually run on Linux and therefore don’t have (or want) iTunes just to install. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-8-installs-customizing-the-pull-to-refresh.html) + + +### **Anonymous** — October 7, 2014 at 11:24 pm ([permalink](https://www.codenameone.com/blog/ios-8-installs-customizing-the-pull-to-refresh.html#comment-22069)) + +> Anonymous says: +> +> That is exactly why we have the ios.plistInject build argument. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-8-installs-customizing-the-pull-to-refresh.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/ios-back-command-behavior.md b/docs/website/content/blog/ios-back-command-behavior.md new file mode 100644 index 0000000000..419297178b --- /dev/null +++ b/docs/website/content/blog/ios-back-command-behavior.md @@ -0,0 +1,104 @@ +--- +title: iOS Back Command Behavior and Facebook Clone Update +slug: ios-back-command-behavior +url: /blog/ios-back-command-behavior/ +original_url: https://www.codenameone.com/blog/ios-back-command-behavior.html +aliases: +- /blog/ios-back-command-behavior.html +date: '2018-04-16' +author: Shai Almog +--- + +![Header Image](/blog/ios-back-command-behavior/pixel-perfect.jpg) + +I’ve been working on the new Facebook clone app, I have a lot to say about that but I’ll defer that for now. One of the things that Facebook did is provide a different experience in iOS & Android. I wanted to replicate that by using a more iOS style back behavior in my clone. + +![Back Command iOS/Android & Facebooks native on Android](/blog/ios-back-command-behavior/facebook-clone-back-command.png) + +Figure 1. Back Command iOS/Android & Facebooks native on Android + +On Android we use an arrow to indicate back but on iOS we usually show the title of the previous form with a `<` icon to indicate the back action. Up until recently this was represented in the `BackCommand` UIID with a an image aligned to the left of the command. This was hard to style and made very little sense. + +With the next update we’ll use the builtin material icon for this when you set a back command. In this form I used the following code for back: + + + getToolbar().setBackCommand(backLabel, + Toolbar.BackCommandPolicy.WHEN_USES_TITLE_OTHERWISE_ARROW, + e -> previous.showBack()); + +The `backLabel` variable represents the title of the previous form. The toolbar policy indicates an arrow will be used on Android and a Title will appear on iOS. + +This will work with the new material font code in the next update (you need to update the skins too). You can disable or force the font image behavior with the new theme constant `iosStyleBackArrowBool=false`. + +### Material Icon Commands + +As part of that work we added three new methods to `Command`: + + + public void setMaterialIcon(char materialIcon); + public void setMaterialIconSize(float size); + public void setIconGapMM(float iconGapMM); + +These allow control over the gap between the icon and the label for the command element as well as set the icon as a material icon. + +We updated a lot of the `Toolbar` code to use these internally so UI will adapt better to changes in UIID’s. + +### Landscape UIID’s + +`setUIID` is a core API that hasn’t changed in ages. We just added a new version of this API that accepts two strings. One represents the UIID in portrait and the other (optional one) can represent a different UIID for landscape. + +__ | If they are the same the other string should be `null` +---|--- + +This allows us to easily implement minor UI changes that make sense when switching orientation e.g. smaller font/padding in the title area. Since that is the chief use case we also added a theme constant which is currently `false` by default: `landscapeTitleUiidBool=true`. + +When you set this to true the UIID’s: `ToolbarLandscape`, `TitleCommandLandscape`, `BackCommandLandscape` &`TitleLandscape` will be used for landscape mode. They all derive their non-landscape versions so just setting the flag to `true` should have no effect. You will need to edit these styles to support this behavior. + +### Container UIID & Font Api’s + +While we are on the subject of UI enhancements we also made a few enhancements to the general API. + +`Container` now accepts a UIID in the constructor with the layout. It’s one less line of code when you create a container. + +We moved the constants from `Font` into the `CN` class and added a couple of helper methods to create fonts more easily. Specifically: + + + public static Font createTrueTypeFont(String fontName); + public static Font createTrueTypeFont(String fontName, float sizeMm); + +So instead of doing: + + + Font n = Font.createTrueTypeFont("native:MainLight", "native:MainLight"). + derive(convertToPixels(3)); + +You can do: + + + Font n = Font.createTrueTypeFont("native:MainLight", 3); + +### Summary + +I hope we won’t break anything with these changes but experience tells me there is always some nuance. Hopefully these will resolve themselves as we move forward. + +I have a lot more to say about the Facebook app, I hope I’ll complete it in time but frankly with my current status it’s a bit doubtful as I’m seriously delayed and back logged. On the plus side what I have so far looks great! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Francesco Galgani** — May 18, 2018 at 7:43 am ([permalink](https://www.codenameone.com/blog/ios-back-command-behavior.html#comment-23915)) + +> Thank you very much for this information, this post helped me on setting correctly the back buttons for iOS and Android. Thank you for all the other news. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-back-command-behavior.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/ios-certificate-wizard.md b/docs/website/content/blog/ios-certificate-wizard.md new file mode 100644 index 0000000000..a0b58ebbbc --- /dev/null +++ b/docs/website/content/blog/ios-certificate-wizard.md @@ -0,0 +1,731 @@ +--- +title: iOS Certificate Wizard +slug: ios-certificate-wizard +url: /blog/ios-certificate-wizard/ +original_url: https://www.codenameone.com/blog/ios-certificate-wizard.html +aliases: +- /blog/ios-certificate-wizard.html +date: '2015-07-07' +author: Steve Hannah +--- + +![Header Image](/blog/ios-certificate-wizard/ios-cert-wizard-blog-post-header.png) + +So you have finished your app and tested it on the simulator. Everything looks good. You’re now ready to proceed with testing on your iPhone. You select the “Send iOS Debug Build” menu item and wait for the build server to work its magic, but then you’re faced with a notice that iOS builds require a valid certificate and provisioning profile. What a hassle! + +If you’ve done any iOS development (not just Codename One) I’m sure you’ve hit this speed-bump before. You can’t **just** test your app on your iPhone. You have to jump through a series of hoops imposed by Apple before you get the privilege of testing your app on your phone. You need to create an App ID with the necessary permissions, generate a certificate signing request, download your certificates, generate mobile provisioning profiles to register your iPhone to be able to test your app. And finally, you have to export your certificates into a format that can be used in Codename One. If you have a Mac, this process is annoying at best. If you don’t, then this process might be your show-stopper. + +Personally, I find the iOS certificate process to be the single most painful part of app development. That is why I’m happy to announce that the next version of the Codename One plugin will include a wizard that generates all of these things for you with just a few mouse clicks. + +## How it works + +To generate your certificates and profiles, simply open your project’s properties, and click on “iOS” in the left menu. This will show the “iOS Signing” panel that includes fields to select your certificates and mobile provisioning profiles. + +![Netbeans iOS Signing properties panel](/blog/ios-certificate-wizard/ios-cert-wizard-1-signing.png) + +If you already have valid certificates and profiles, you can just enter their locations here. If you don’t, then you can use the new wizard by clicking the “Generate” button in the lower part of the form. + +### Logging into the Wizard + +After clicking “Generate” you’ll be shown a login form. Log into this form using your **iTunes Connect** user ID and password. **NOT YOUR CODENAME ONE LOGIN**. + +image::/img/blog/ios-cert-wizard-2-login.png[Wizard login form] + +### Selecting Devices + +Once you are logged in you will be shown a list of all of the devices that you currently have registered on your Apple developer account. + +![Devices form](/blog/ios-certificate-wizard/ios-cert-wizard-3-devices.png) + +Select the ones that you want to include in your provisioning profile and click next. + +![After selecting devices](/blog/ios-certificate-wizard/ios-cert-wizard-4-devices-selected.png) + +If you don’t have any devices registered yet, you can click the “Add New Device” button, which will prompt you to enter the UDID for your device. + +### Decisions & Edge Cases + +After you click “Next” on the device form, the wizard checks to see if you already have a valid certificate. If your project already has a valid certificate and it matches the one that is currently active in your apple developer account, then it will just use the same certificate. If the certificate doesn’t match the currently-active one, or you haven’t provided a certificate, you will be prompted to overwrite the old certificate with a new one. + +![Prompt to overwrite existing certificate](/blog/ios-certificate-wizard/ios-cert-wizard-4.1-overwrite-cert.png) + +![Prompt to overwrite other certificate](/blog/ios-certificate-wizard/ios-cert-wizard-4.2-overwrite-cert.png) + +The same “decisions” need to be made twice: Once for the development certificate, and once for the Apptore certificate. + +### App IDs and Provisioning Profiles + +The next form in the wizard asks for your app’s bundle ID. This should have been prefilled, but you can change the app ID to a wildcard ID if you prefer. + +![Enter the app bundle ID](/blog/ios-certificate-wizard/ios-cert-wizard-5-bundle-id.png) + +### Installing Files Locally + +Once the wizard is finished generating your provisioning profiles, you should click “Install Locally”, which will open a file dialog for you to navigate to a folder in which to store the generated files. + +![Install files locally](/blog/ios-certificate-wizard/ios-cert-wizard-6-install-now.png) + +![Select directory to save files in](/blog/ios-certificate-wizard/ios-cert-wizard-7-select-directory.png) + +![All done](/blog/ios-certificate-wizard/ios-cert-wizard-8-complete.png) + +### Building Your App + +After selecting your local install location, and closing the wizard, you should see the fields of the “iOS Signing” properties panel filled in correctly. You should now be able to send iOS debug or Appstore builds without the usual hassles. + +![Filled in signing panel after wizard complete](/blog/ios-certificate-wizard/ios-cert-wizard-9-signing-panel.png) + +## Future Improvements + +This wizard is just the next step in our mission to simplify the app-development process. In the next while we’ll be rolling out more features like this. Some planned features include push certificate generation and Appstore uploads. If there are particular aspects of the app development and deployment process that you still find cumbersome, make sure to let us know so we can work on finding solutions. + +## Screencast + +If you want to see the wizard in action, you can check out this 2 minute screencast. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Chidiebere Okwudire** — July 19, 2015 at 1:10 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-21550)) + +> Great work, guys! I’ll try this out in the coming weeks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Lukman Javalove Idealist Jaji** — July 20, 2015 at 8:23 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22020)) + +> Why do we have to select devices? Is that for testing purposes only? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — July 20, 2015 at 2:43 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22240)) + +> Yes. Apple allows running on up to 100 devices and you need to add them to your account as testers. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Clement Levallois** — July 23, 2015 at 8:36 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22384)) + +> After selecting my device and clicking on Next I get an error saying that my session has expired and I should login again? See pic attached +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **shannah78** — July 23, 2015 at 1:17 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22401)) + +> Not sure yet what would cause that. If you log into your Apple developer account are there any pending agreements that you have to agree to? Are you able to access the “create certificate form” in your apple developer account? Also, does your account have multiple teams? (i.e. when you log into apple developer to you need to select a team?) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **shannah78** — July 23, 2015 at 3:38 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22194)) + +> Actually I have just made some fixes to the wizard. Please try again and it should work. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Clement Levallois** — July 23, 2015 at 7:20 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22231)) + +> It wooorks! Amazing, takes just 2 seconds. Congrats on an amazing job for the community! 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **sao** — July 28, 2015 at 3:16 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-21495)) + +> This is a great achievement. Well done CodeNameOne team +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Tom Arn** — August 5, 2015 at 1:05 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22315)) + +> That’s fantastic! Especially if you are developping on Windows, certificate creation was such a pain! Very well done! +> +> If I could also do the appstore upload from the Codename One plugin as planned, then I could finally cease using MacInCloud again. +> That would be an even better enhancement than the certificate wizard, because I do a lot more uploads than I need to create certificates! +> +> Tom +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — August 5, 2015 at 2:03 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22323)) + +> It was something we wanted to add but the deployment complexity is far bigger. +> I want it too since that’s pretty much the only reason to own a Mac and we have at least the rudimentary understanding of how to do that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Chidiebere Okwudire** — August 13, 2015 at 3:54 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22021)) + +> Chidiebere Okwudire says: +> +> Hi Steve, +> +> I tried the wizard and it works just fine. However, I have two test apps and I noticed that after using the wizard to generate certificates for the second app, the first one’s certificates are marked as ‘invalid’ and the app no longer runs on my device. Is this a restriction from Apple or from the wizard? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — August 13, 2015 at 4:23 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22140)) + +> Shai Almog says: +> +> The wizard asks you if you already have P12 files otherwise it regenerates them for you and effectively invalidates the old ones. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Chidiebere Okwudire** — August 13, 2015 at 7:24 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22365)) + +> Chidiebere Okwudire says: +> +> So are you saying that I can use the p12 files generated for the first app in all others? I vaguely remember that the build failed when I tried that but I’ll have to recheck based on your answer. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Sanny Sanoff** — August 14, 2015 at 8:50 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-24180)) + +> Sanny Sanoff says: +> +> Wizard button did not appear in the place described here. IDEA 14/15. +> Installed Macos, Xcode and attached developer account to xcode, tested device build. Restarted IDEA. No luck. +> Moreover, in IDEA preferences, there are 2 instances of Codename One configuration nodes. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — August 14, 2015 at 1:14 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22419)) + +> Shai Almog says: +> +> That feature isn’t available yet in the IntelliJ version of the plugin. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Barak** — November 10, 2015 at 11:41 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22152)) + +> Barak says: +> +> After pressing generate and logging in to my Itunes account +> I get this message(attached image) +> any idea how to fix it? +> +> Thanks in advance. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — November 11, 2015 at 4:55 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-21614)) + +> Shai Almog says: +> +> You shouldn’t get that message so its definitely a bug. Is the page [http://developer.apple.com/…]() reachable or do you see notices that you need to approve something? +> Dismissing Apple notices is horribly unintuitive. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Barak** — November 11, 2015 at 6:35 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-24172)) + +> Barak says: +> +> Everything seems fine in that page ,I suppose I didn’t ‘enroll’ and paid the 100$ fee. +> I hope that’s not the problem… +> is it? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — November 11, 2015 at 8:01 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22220)) + +> Shai Almog says: +> +> You need to pay Apple and wait for approval which takes a couple of days. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Barak** — November 11, 2015 at 3:39 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22234)) + +> Barak says: +> +> Well that’s unfortunate,thanks anyway! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Yngve Moe** — November 14, 2015 at 5:58 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22415)) + +> Yngve Moe says: +> +> I can’t see any login dialog. When i press Generate, I just get the message “This feature requires you to be logged in.” This happens on a fresh install of NetBeans with Codename One plugin, both on Mac and Windows. Am i doing something wrong? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — November 15, 2015 at 4:12 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22488)) + +> Shai Almog says: +> +> Yes, I think its a mistake to require that. It was added to simplify the process of generating push certificates. +> You login in the main Codename One section of the preferences at the bottom of the UI. That might be hidden if you have a small screen. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Yngve Moe** — November 15, 2015 at 10:29 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22299)) + +> Yngve Moe says: +> +> You’re right, that section was hidden. I found it myself after some googling. Apart from that, the wizard is very simple and smooth – saved me a lot of work! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Andrey** — December 21, 2015 at 1:24 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22506)) + +> Andrey says: +> +> I used the free version Codename one and Intellij IDEA. Why is there no button generate? What should I do to make it come from? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — December 22, 2015 at 5:56 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22599)) + +> Shai Almog says: +> +> The certificate wizard is available for free. The IntelliJ plugin is a bit out of date with many new features such as Java 8 support etc. +> We are working on a complete overhaul of the plugin but get side tracked a lot. I hope we’ll be able to bring it into feature parity with the current NetBeans/Eclipse plugins for 3.3. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Andrey** — December 22, 2015 at 9:41 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22532)) + +> Andrey says: +> +> Shai, thanks for answer. I will try to set up Eclipse or NetBeans. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Andrey** — December 23, 2015 at 3:12 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22360)) + +> Andrey says: +> +> Shai, can you answer me, in last version Eclipse for java developers (mars) is there this button? I don’t found that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — December 24, 2015 at 10:21 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22185)) + +> Shai Almog says: +> +> This is what I’m seeing, how did you install the plugin? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **tomm0** — January 19, 2016 at 3:47 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22658)) + +> tomm0 says: +> +> Does each app needs its own Certificate? I am confused by that aspect. I have just been testing things out, and whenever I choose to Overwrite the certificate I get an email from Apple saying my certificate has been revoked. What should the general process be? Should each app have its own p12 certificate? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — January 20, 2016 at 3:41 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22515)) + +> Shai Almog says: +> +> That should indeed be clearer in the wizard, I’m not exactly sure how we can do that though… +> +> You need one set of signing certificates for all your apps. You need to renew them once per year as they do expire. +> +> Provisioning profiles are done per-app so when you run the wizard on a new app just tell it NO when it asks to generate the certificates and point the UI to the P12 files you generated last! +> +> Now this is the point where it gets hard… When doing push you DO need new P12 files that are specific to the app, they are totally unrelated to signing/building and are only used for push. So if you check the “push” checkbox you will need to generate those. You will get an automatic email message with instructions when you check that flag. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Paul Willworth** — January 25, 2016 at 6:06 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-21492)) + +> Paul Willworth says: +> +> This is a great feature. The one thing I don’t understand is where it gets the certificate passwords from. I can complete the wizard process successfully, but when I’m done I find that it has used the value “password” for my certificate passwords. I don’t want it to use that, how do I specify what password the wizard should use for my certificates? I am using Eclipse. I saw some talk in another thread about setting some project level password but I don’t see that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — January 26, 2016 at 3:16 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22516)) + +> Shai Almog says: +> +> I don’t think that’s configurable for the build p12 files. Notice that the security of those files isn’t crucial as they are stored on your local machine. Normally on a Mac when building locally the keys are just protected by your OS password. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **James Mason** — May 24, 2016 at 12:48 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22632)) + +> James Mason says: +> +> When I run the iOS Certificate Wizard, a window pops up saying “Select Team”. But no teams are listed and there is no response to the Next button either. How do I get beyond this? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — May 25, 2016 at 5:57 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22643)) + +> Shai Almog says: +> +> If you navigate to [http://developer.apple.com/…]() do you see teams or something like that? +> Do you have the ability to create a new certificate/provisioning profile? +> +> Is there something “special” about your account? (Enterprise, University etc.) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **James Mason** — May 25, 2016 at 4:03 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22869)) + +> James Mason says: +> +> Thanks very much, Shai, for pointing me in the right direction. I think Codename One is great and have used it successfully with no problems to develop an Android app. Now, not being an Apple person, I just have to get by their hurdles to become a registered iOS developer. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **3lix** — August 22, 2016 at 6:24 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22814)) + +> 3lix says: +> +> Hello I am getting the following error “could not create development profile. No matching provisioning profile was found” when I try to generate the certificated. +> I do have a developer account which I use to login with. (this step is successful) +> Selecting device step is also successful as I see the newly added device on my developer’s account. +> I would appreciate any help. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Ian** — August 22, 2016 at 9:35 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-21654)) + +> Ian says: +> +> Hi. I’m trying to use the wizard to generate a certificate. It worked fine previously but now, it isn’t working. It asks me for the devices, I select them, it asks if I want to overwrite existing iOS certificate and I say “Yes”. +> +> But then it doesn’t generate any certificate. Any idea why? I don’t get any error message. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **3lix** — August 22, 2016 at 3:08 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22913)) + +> 3lix says: +> +> Also I noticed that my “Certificates” screen shows up with “Enable Push Pro Feature only” at the bottom. +> I am not sure if this is causing any issues? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — August 24, 2016 at 8:03 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22588)) + +> Shai Almog says: +> +> There was an issue with Apple changing it’s certificate process, we’ve deployed an update that should fix this. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — August 24, 2016 at 8:04 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22978)) + +> Shai Almog says: +> +> There was an issue with Apple changing it’s certificate process, we’ve deployed an update that should fix this. +> +> The enable push is unrelated. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **3lix** — August 24, 2016 at 3:09 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22684)) + +> 3lix says: +> +> Thank you very much! Looks like its working now, +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **hesham mohamed** — October 20, 2016 at 9:09 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23125)) + +> hesham mohamed says: +> +> Hello, i am getting same Message (Select team ), and i checked my Apple account and i can’t see anything like teams, and don’t know what could be the reason behind ! +> appreciate your help +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Jacob Rachoene** — October 27, 2016 at 10:42 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-22796)) + +> Jacob Rachoene says: +> +> Hi James, have you actually figured out your way around this? Exactly what did you do? Any one has an idea? +> Thanks… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — October 28, 2016 at 3:45 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23159)) + +> Shai Almog says: +> +> You need to have a paid Apple account for this to work +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shubhanjan Medhi** — January 26, 2017 at 10:22 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23027)) + +> Shubhanjan Medhi says: +> +> Hi, i am unable to generate a certificate using the wizard, it asks me to select a team but there is no team listed. I tried logging into my apple account [https://developer.apple.com…]() but even there i could not find any certificate for signing. +> +> How do i do it? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — January 27, 2017 at 7:33 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23220)) + +> Shai Almog says: +> +> Hi, +> do you have a paid iOS developer account? +> Can you generate a CSR in your apple account? +> +> That’s a requirement to generating the certificate. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Kai** — February 3, 2017 at 10:16 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23326)) + +> Kai says: +> +> Hi, +> I am using a university dev account, I know that I cannot create Appstore certificates. +> Using the ios Signing wizard from Codenameone settings panel (NetBeans, latest Plug-in), +> everything works so far and the certificate + provisioning profile + appid get created. +> However the needed certificate password is not stored in the [codenameone_settings.proper…]() file. +> Is there a bug? Otherwise I’m having troubles as I do not own a Mac for the CSR. +> Additionally the created files (I downloaded them from the developer account website, as I couldn’t find them on my system) do not get added into the related fields. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Kai** — February 3, 2017 at 3:21 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23097)) + +> Kai says: +> +> I fixed it by creating the .p12 file on my own. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — February 4, 2017 at 8:34 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-24124)) + +> Shai Almog says: +> +> Hi, +> this should work even with a university account +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Kai** — February 6, 2017 at 9:08 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23104)) + +> Kai says: +> +> Hi, unfortunately it only creates a .cer file and not the needed .p12 file +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — February 7, 2017 at 10:08 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23118)) + +> Shai Almog says: +> +> I’m assuming you downloaded the cer files from the apple site and didn’t generate them via the tool. Right? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Kai** — February 7, 2017 at 10:44 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23127)) + +> Kai says: +> +> No, I used the tool for the whole process. It shows that the AppStore certificate was not generated, after setting App Name (you should add validation that no special characters are allowed) & App ID, it runs into an error “Could not create appstore profile. No matching provisioning profile was found”. Then it returns to the view where App name and ID are set. Then I tried to download the files from [developer.apple.com](), because I couldn’t find any generated/downloaded file on my system, neither are any paths/settings set in the Codenameone ios signature settings. +> In my case I managed to create the .p12 file and build iOS debug-app, but I could not use the wizard at all. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — February 8, 2017 at 9:05 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23236)) + +> Shai Almog says: +> +> Then you did download the cer file. P12 files aren’t generated by Apple they can only be generated thru the wizard. Unfortunately we can’t debug the university accounts since we aren’t an educational institute. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Tommy Mogaka** — February 17, 2017 at 8:43 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23164)) + +> Tommy Mogaka says: +> +> Hi Steve… great post and awesome work you guys doing. CN1 is one of the great enablers and equalizers out there. +> One thing I would like to see is the App Store upload process especially for Apple. Right now I have a challenge as using the Application Loader 3.0 fails saying it is not available right now and that no suitable application records were found and that I should upload my bundle identifier…. What could be the cause of this? And how can I resolve this problem? My App name and App ID as written in netbeans initially didn’t match the one on the developer portal. I edited the portal to match Netbeans but no luck. Any ideas? Any pointers will be highly appreciated. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Tommy Mogaka** — February 17, 2017 at 9:24 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23360)) + +> Tommy Mogaka says: +> +> Got the issue! I had not selected the correct Bundle ID under General information of the app in the developer portal. Now I am getting this error: +> ERROR ITMS-90168: “The binary you uploaded was invalid” +> Looks like I have to start over… will clean out the portal of any id, certs and profiles and try again. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — February 18, 2017 at 10:47 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23190)) + +> Shai Almog says: +> +> It’s a painful process the first time around. We’d like to add an upload to itunes wizard at some point but it’s not a trivial task. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Chris** — June 16, 2017 at 5:51 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23586)) + +> Chris says: +> +> Hi Shai, I’m encountering same issue now. is there any fix needed on codename server. Through the wizard it says Developer Cert not Generated and Appstore cert not generated. When I complete the process, it creates profiles and certificates but the passwords showing empty. Build is getting failed. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — June 16, 2017 at 7:06 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23200)) + +> Shai Almog says: +> +> It’s a regression due to some server changes we made see [https://groups.google.com/d…]() +> Should be fixed now +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **beck** — September 6, 2017 at 5:57 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23746)) + +> beck says: +> +> “I’m happy to announce that the next version of the Codename One plugin will include a wizard that generates all of these things for you with just a few mouse clicks.” Has it happened yet? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — September 7, 2017 at 8:17 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23627)) + +> Shai Almog says: +> +> This is a post from 2015… It happened 2 years ago. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Json** — September 15, 2017 at 11:21 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-21472)) + +> Json says: +> +> I’m faced with the same problem.. I’m developing 2 apps, been test building on android with no problems and wanted to do test iOS builds, the howto above is great and I was able to send a debug build and install etc.. however when trying to do the same for the second app I’m stuck, I used the same wizard.. _DID_NOT_ create a new signing cert (as I thought it would invalidate the original certs and it looks like I’m correct) and only got the provisioning profiles created. My question is how do we use the same certs for other apps when we dont know the password? I get build errors which I suspect may be caused by the fact that I dont know the password for the certificates in the first place =( +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — September 16, 2017 at 5:19 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23769)) + +> Shai Almog says: +> +> You need to copy the P12 files from the other project into your new project and update then in the iOS signing section with their passwords. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Json** — September 17, 2017 at 1:21 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23531)) + +> Json says: +> +> thanks shai! ok I figured out the default password for the p12, certs.. its in the properties file of the other project (of course!), I was able to generate the ios build for the second project with the same cert but diff provisioning profile. +> +> my hats off to you and your team! — from a 20 something year java veteran + 2 week CN1 dev =) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **ZombieLover** — March 18, 2018 at 4:27 pm ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-21535)) + +> ZombieLover says: +> +> So we can’t produce apple builds without having a paid Apple account then? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **Shai Almog** — March 19, 2018 at 5:33 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23870)) + +> Shai Almog says: +> +> That’s an Apple restriction. When we launched we provided an option to sign with our own certificate but we removed that as we think it violates Apples terms of service. For that to work you had to have a jailbroken device and that’s not a practical requirement today. +> +> Apple provides free certificates for educational institutes & non-profits so you might be able to obtain a certificate through one of those venues. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + + +### **ZombieLover** — March 19, 2018 at 6:03 am ([permalink](https://www.codenameone.com/blog/ios-certificate-wizard.html#comment-23897)) + +> ZombieLover says: +> +> Thanks for the quick reply +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-certificate-wizard.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/ios-code-signing-fail-checklist.md b/docs/website/content/blog/ios-code-signing-fail-checklist.md new file mode 100644 index 0000000000..a3fc122eea --- /dev/null +++ b/docs/website/content/blog/ios-code-signing-fail-checklist.md @@ -0,0 +1,276 @@ +--- +title: iOS Code Signing Fail Checklist +slug: ios-code-signing-fail-checklist +url: /blog/ios-code-signing-fail-checklist/ +original_url: https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html +aliases: +- /blog/ios-code-signing-fail-checklist.html +date: '2013-10-06' +author: Shai Almog +--- + +![Header Image](/blog/ios-code-signing-fail-checklist/ios-code-signing-fail-checklist-1.png) + + + + +[ +![Export P12](/blog/ios-code-signing-fail-checklist/ios-code-signing-fail-checklist-1.png) +](/img/blog/old_posts/ios-code-signing-fail-checklist-large-8.png) + + + +This is one of the biggest FAQ’s we get on the mailing list: I followed the iOS +[ +signing tutorial +](/signing.html) +or +[ +video tutorial +](/how-do-i.html) +and still didn’t succeed in signing (notice that you need to actually read the links above, the certificate you get from the apple website is not enough!). + + + +How do I debug something like this? + +Notice that some of these signing failures will sometimes manifest themselves during build and sometimes will manifest during the install of the application. + + + + + +Well, there are several steps we always need to follow when troubleshooting such issues: + + + 1. +You +_ +** +must +** +_ +use a Mac to generate the P12 certificates. There is no way around it! (tutorials that show otherwise will not work). + +We would like to automate it in the future (in a similar way to our Android signing tool), but for now you can use +[ +MacInCloud +](http://www.macincloud.com/) +which has a free version. + +Notice that this is something you need to do once a year (generate P12), you will also need a Mac to upload your final app to the store though. + + 2. +When exporting the P12 certificate make sure that you selected BOTH the public and the private keys as illustrated in the image to the right. + + 3. +Make sure the package matches between the main preferences screen in the IDE and the iOS settings screen (see pictures below). + + 4. +Make sure the prefix for the app id in the iOS section of the preferences matches the one you have from Apple + +(see pictures below) + +. + + 5. +Make sure your provisioning profile’s app id matches your package name or is a * provisioning profile. Both are sampled in the pictures below, notice that you would need an actual package name for push/in-app-purchase support as well as for app store distribution. + + 6. +Make sure the certificate and provisioning profile are from the same source (if you work with multiple accounts), notice that provisioning profiles and certificates expire so you will need to regenerate provisioning when your certificate expires or is revoked. + + 7. +If you declare push in the provisioning profile then ios.includePush (in the build arguments) MUST be set to true, otherwise it MUST be set to false + +(see pictures below) + +. + + + + +Did this help you? Let us know in the comments. + +* * * + +[ +![](/blog/ios-code-signing-fail-checklist/ios-code-signing-fail-checklist-2.png) +](/img/blog/old_posts/ios-code-signing-fail-checklist-large-9.png) + +[ +![](/blog/ios-code-signing-fail-checklist/ios-code-signing-fail-checklist-3.png) +](/img/blog/old_posts/ios-code-signing-fail-checklist-large-10.png) + +[ +![](/blog/ios-code-signing-fail-checklist/ios-code-signing-fail-checklist-4.png) +](/img/blog/old_posts/ios-code-signing-fail-checklist-large-11.png) + +[ +![](/blog/ios-code-signing-fail-checklist/ios-code-signing-fail-checklist-5.png) +](/img/blog/old_posts/ios-code-signing-fail-checklist-large-12.png) + +[ +![](/blog/ios-code-signing-fail-checklist/ios-code-signing-fail-checklist-6.png) +](/img/blog/old_posts/ios-code-signing-fail-checklist-large-13.png) + +[ +![](/blog/ios-code-signing-fail-checklist/ios-code-signing-fail-checklist-7.png) +](/img/blog/old_posts/ios-code-signing-fail-checklist-large-14.png) + + + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — October 8, 2013 at 12:37 pm ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-22046)) + +> Anonymous says: +> +> MacCloud has a free option, I did not see that. +> +> This blog was a life-saver. I just went through this, and had a myriad of problems, compounded by my own stupidity, and my ignorance of ios App development and Mac in general. +> +> The saving of the two keys tripped me up. Seemed subtle in the video, and easily missed. +> +> Regarding the AppId, Might I suggest, since you are taking both properties, +> +> codename1.packageName, and codename1.ios.appid, +> +> you have Ant or some other preprocessor check to see that the ending of the appid conforms to the packageName before the build is sent to the server. I had this wrong yesterday and was able to initiate a server side build (followed) certificate errors. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — October 8, 2013 at 5:38 pm ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-21973)) + +> Anonymous says: +> +> Thanks! +> +> There are indeed a lot of things we need to do and can do on the client side before actually sending the build to the server. I think there is even an issue for the various types of static analysis we can perform locally, unfortunately we never got around to doing that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — March 6, 2014 at 3:25 pm ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-22022)) + +> Anonymous says: +> +> Thank you, this is an extremely useful post. One thing to add (in case someone stumbles upon the same problem): +> +> When exporting private key / certificate pair from Mac’s keychain you will be prompted for a password to protect your private key. You _MUST_ enter a password that is at least 4 characters long – there will be no warnings / errors if you don’t, but build signing will quietly fail. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — July 14, 2014 at 9:47 pm ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-24215)) + +> Anonymous says: +> +> (3) Make sure the package matches between the main preferences screen in the IDE and the iOS settings screen (see pictures below). +> +> Im my mac, dont existe option to “export 2 files” +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — July 14, 2014 at 9:48 pm ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-21916)) + +> Anonymous says: +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — August 9, 2014 at 3:56 pm ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-21949)) + +> Anonymous says: +> +> I return to this problem once a year. How do I extract proper mobile provision files from development environment? I spend around hour each time, macos is very alien environment. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — August 10, 2014 at 3:19 am ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-21678)) + +> Anonymous says: +> +> There is a tutorial covering this in the How Do I section. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — September 22, 2014 at 3:50 am ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-22134)) + +> Anonymous says: +> +> An important omission is that sometimes install fails on the device the first time around thru the link/QR code but succeeds via itunes. This is due to provisioning profile configuration on the device and seems to be an Apple bug. +> +> After installing once with itunes future installations should work thru the QR code. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — February 13, 2015 at 5:57 am ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-22352)) + +> Anonymous says: +> +> I just wanted to share with you that (despite what it says in Point 1.) I have successfully created a development P12 certificate on my Windows machine using XCA. I followed the steps described here: +> +> [http://smarttechie.org/2013…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — February 13, 2015 at 1:30 pm ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-22018)) + +> Anonymous says: +> +> Did you get a build passed? +> +> With the old VM? New VM? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — February 13, 2015 at 4:16 pm ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-24166)) + +> Anonymous says: +> +> I don’t know which VM. I just sent the build to the build servers along with the p12 certificate and it installed all right on my iPhone. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — February 14, 2015 at 3:33 am ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-21997)) + +> Anonymous says: +> +> The default is the new VM with xcode 6. If you set ios.newVM=false I’m guessing your build will fail. Can you verify this? +> +> If so it might mean the new VM has another nice advantage over the old VM. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + + +### **Anonymous** — February 17, 2015 at 10:48 am ([permalink](https://www.codenameone.com/blog/ios-code-signing-fail-checklist.html#comment-24188)) + +> Anonymous says: +> +> It also works with set ios.newVM=false but the new VM seems to work better. +> +> Tom +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-code-signing-fail-checklist.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/ios-http-urls.md b/docs/website/content/blog/ios-http-urls.md new file mode 100644 index 0000000000..eaab2cd62e --- /dev/null +++ b/docs/website/content/blog/ios-http-urls.md @@ -0,0 +1,77 @@ +--- +title: iOS Http URL's +slug: ios-http-urls +url: /blog/ios-http-urls/ +original_url: https://www.codenameone.com/blog/ios-http-urls.html +aliases: +- /blog/ios-http-urls.html +date: '2016-06-15' +author: Shai Almog +--- + +![Header Image](/blog/ios-http-urls/xcode-migration.jpg) + +We’ll be [migrating to the new iOS build servers](/blog/ios-server-migration-plan.html) +this Sunday & this does entail one major thing you need to be aware of. With the new version of xcode http +URL’s [are blocked by Apple](/blog/hiding-url-security-advocacy.html). We +blogged about this a while back but this bares repeating as it’s something a lot of you will start running into. + +To get an overview of the issue check out +[this article](http://code.tutsplus.com/articles/apple-tightens-security-with-app-transport-security—​cms-24420) or +the [actual document from Apple](https://developer.apple.com/library/mac/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html). +In a nutshell http URL’s are no longer supported by Apple to facilitate proper security. + +You can disable this block by using the build hint +`ios.plistInject=NSAppTransportSecurityNSAllowsArbitraryLoads` +but if you don’t have a good reason to do this Apple will reject your app and won’t let you ship your app +thru the appstore. + +Be sure to update your apps! + +Starting with this update our simulator will print out a warning every time you try to connect to an HTTP URL +to help you detect the cases where you do so. Hopefully this will make the migration to the new servers smoother. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Gareth Murfin** — June 16, 2016 at 5:02 pm ([permalink](https://www.codenameone.com/blog/ios-http-urls.html#comment-22893)) + +> Gareth Murfin says: +> +> So HttpS will be fine right? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-http-urls.html) + + +### **Shai Almog** — June 17, 2016 at 3:40 am ([permalink](https://www.codenameone.com/blog/ios-http-urls.html#comment-22827)) + +> Shai Almog says: +> +> That’s the goal. To force apps to use proper https sites and proper security. +> I understand the logic here. In a browser you can see the lock icon on the top left and know if you are submitting to a secure website. In an app there is no such indication. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-http-urls.html) + + +### **Eric Coolman** — July 1, 2016 at 11:24 pm ([permalink](https://www.codenameone.com/blog/ios-http-urls.html#comment-22704)) + +> Eric Coolman says: +> +> ATS minimum defaults: HTTPS + TLS 1.2 + FS +> +> [https://developer.apple.com…]() +> +> So far we haven’t been flagged for enabling arbitrary loads support with our banking apps, but I’m sure Apple will start clamping down soon. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-http-urls.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/ios-migration-continued.md b/docs/website/content/blog/ios-migration-continued.md new file mode 100644 index 0000000000..89d5c6ae39 --- /dev/null +++ b/docs/website/content/blog/ios-migration-continued.md @@ -0,0 +1,87 @@ +--- +title: iOS Migration Continued +slug: ios-migration-continued +url: /blog/ios-migration-continued/ +original_url: https://www.codenameone.com/blog/ios-migration-continued.html +aliases: +- /blog/ios-migration-continued.html +date: '2016-06-08' +author: Shai Almog +--- + +![Header Image](/blog/ios-migration-continued/xcode-migration.jpg) + +We announced our [plans to migrate to the newest version of xcode](/blog/ios-server-migration-plan.html) +recently and so far these plans have gone rather well with most tests passing without a problem. We did decide +to disable bitcode by default which means the new build hint `ios.bitcode` will now default to `false` to avoid issues +with some libraries that are still not up to date. + +One point of confusion from that update was whether `iphone_new` should still be used. The answer is **NO**. + +You should use the `iphone` build target as before and we will switch the servers seamlessly. + +We will perform the migration to the new servers over the course of the next 2 months as we prepare for 3.5. +Since 3.5 is slated for early August we’d like to have the new servers in place by then…​ + +### Switch Transitory Period + +During the switch transitory period we will allow building to a special `iphone_old` target to workaround potential +server regressions. If you built to the `iphone_new` this is the same thing and you should skip ahead if not then +read this for instructions on how to temporarily workaround regressions. + +__ | You **MUST** report all regressions to us at once! +If you don’t file issues we will not know a regression exists and might continue the migration plan assuming everything +works. +---|--- + +Open the `build.xml` file & search for the string `"iphone"` **with the quotes**. +Replace it with `"iphone_old"` . + +E.g. notice the `targetType="iphone_old"` line below: + + + + + + +### Trial Switch + +On Sunday June 19th we will switch to the new build servers so all standard `iphone` builds will reach the new +servers. We will also setup the old servers as iphone_old servers. + +On that day some builds might get “lost” in the ether of migration so if a build gets stuck cancel it…​ + +This will be a trial run, if everything will “just work” which is a possibility (however unlikely) this will be it. + +However, if issues are reported we will probably revert back to the old servers. + +### Complete Switch + +Assuming the trial teaches us about some issues we might do another trial but our final switch target date is +July 3rd. Assuming things mostly work our correctly we aim to bring down some of our build server capacity for +OS upgrade in preparation of the full switch. + +This will mark the full switch to the new version of xcode. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/ios-migration-setback.md b/docs/website/content/blog/ios-migration-setback.md new file mode 100644 index 0000000000..032b5f4172 --- /dev/null +++ b/docs/website/content/blog/ios-migration-setback.md @@ -0,0 +1,40 @@ +--- +title: iOS Migration Setback +slug: ios-migration-setback +url: /blog/ios-migration-setback/ +original_url: https://www.codenameone.com/blog/ios-migration-setback.html +aliases: +- /blog/ios-migration-setback.html +date: '2016-06-19' +author: Shai Almog +--- + +![Header Image](/blog/ios-migration-setback/xcode-migration.jpg) + +A couple of weeks ago we [detailed a plan](/blog/ios-migration-continued.html) to migrate to the new xcode 7.x +build servers. We tried this migration over the weekend and while for most developers this worked rather nicely +for some there were issues that we can’t explain so we decided to revert the change and regroup. + +We want this transition to be smoother than past transitions and since we aren’t currently working against a +deadline we feel we have some time to refine this migration to a point where it will be seamless for all/most +of our users. + +We don’t have a set date to retry the migration but we are currently aiming for 2-3 weeks from now. + +The main issue involves the rather elaborate build script we have in place since the days of xcode 4.x. It seems +that for some applications or provisioning profiles xcode just crashes…​ + +The solution is probably to build the application in a rather different way than we current do which might not crash +xcode but unfortunately this will make this change & migration more complicated than we initially hoped so the +sensible solution seems to be to move back to the `iphone_new` mode and make builds go to the old servers +while we experiment. + +We will announce details of the second attempt at migration in this blog…​ + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/ios-server-migration-plan.md b/docs/website/content/blog/ios-server-migration-plan.md new file mode 100644 index 0000000000..c27844f130 --- /dev/null +++ b/docs/website/content/blog/ios-server-migration-plan.md @@ -0,0 +1,150 @@ +--- +title: iOS Server Migration Plan +slug: ios-server-migration-plan +url: /blog/ios-server-migration-plan/ +original_url: https://www.codenameone.com/blog/ios-server-migration-plan.html +aliases: +- /blog/ios-server-migration-plan.html +date: '2016-05-24' +author: Shai Almog +--- + +![Header Image](/blog/ios-server-migration-plan/xcode-migration.jpg) + +We were stuck on an “old” version of xcode in the build servers. This hasn’t been a big deal for most features +but in some cases we are running into issues e.g. in using the full capabilities of the new iPad or 3d touch. The reason +for this is Apples backwards compatibility policy. + +Apple allows you to run an older version of xcode, but the newer versions of xcode always require the latest +version of Mac OS X. The problem here is that the latest version of Mac OS X doesn’t support older versions +of xcode so if we upgrade we won’t be able to support older versions of the build…​ + +Normally this shouldn’t be a problem, we already run fine on the latest version of xcode without a problem. However, +you might inadvertently have relied on some behaviors or functionality of the old xcode e.g. thru native code, +third party cn1lib or slight behavior variation. + +Unfortunately, this means that once we upgrade there is no way to turn back. We’ll need to update the OS’s of +the build servers and do this consistently so you will get consistent build results. This would also mean that some +aspects of versioned builds will not work as smoothly as the new iOS build servers won’t have the older version +of xcode in place. + +### The Migration Plan + +We’ve setup a new build server as a “test pilot” to see that builds go thru as planned. You can/should test your +app to see if it will be affected by the migration, please let us know immediately if there are issues! + +__ | If you don’t do this we will not be able to go back! +---|--- + +To test your app on the test pilot build server open the build.xml and search for the string `"iphone"` **with the quotes**. +Replace it with `"iphone_new"` . + +E.g. notice the `targetType="iphone_new"` line below: + + + + + + +Assuming all goes well we will flip the switch and update some of the build servers to the latest OS. We’ll keep +one build server around with the legacy OS and change it so you will need to explicitly send a build to it…​ + +This effectively means you will need to revert this `build.xml` change to keep building as the new servers will +then use the “iphone” target. To build for the old build target you will need to do the inverse of the current change +by sending a build to the `"iphone_old"` target. + +We’ll support that for a while until we are convinced that the migration went smoothly at which point we will retire +the server. + +From past experience these things always generate issues for some developers that can sometimes take a while +to resolve. That’s why it’s important to keep a legacy build server around. Unfortunately our experience here +also taught us that once we provide a workaround people use that and don’t test the new update. + +The nice thing about this switch is that most developers won’t really feel it. Your builds will use newer +iOS capabilities without a single change made by you. + +#### Bitcode + +Probably the biggest issue with the migration is bitcode support which was introduced a while back. To understand +bitcode you need to understand a bit of the background…​ + +iOS applications are really Mac OS app bundles. The natively compiled binary can contain more than one processor +architecture and usually does. So by default when you build an iOS appstore build you are really building a 32 bit +and 64 bit fat binary. Assuming you want to support the (Apple native) simulator too you will also need x86 binaries +and this is just a partial list…​ + +When we look into more esoteric devices like the Apple Watch or TV things become more complicated and would +obviously become worse as a result. + +This is the problem bitcode aims to solve. Since Apple already uses LLVM which has an intermediate representation +after compilation they might as well use that instead of the native OS executables. This would allow Apples servers +to natively compile the app to any future processor platform without you changing your code…​ Effectively this is +very much like a form of bytecode for Apples benefit. + +Bitcode is required for Apple Watch apps and might become required for all apps in the future so it’s a good idea +to leave it on. + +The main challenge with bitcode is 3rd party libraries, if you use any of those they need to be compiled with bitcode +support enabled otherwise the compiler will fail. Many libraries (especially older ones) don’t have bitcode support +so you might need to update native code to include that functionality. + +We intend to offer a flag to disable bitcode before we go into production with this version, however right now it’s +not in the current version. + +### Zlib QR/Barcode Support + +A while back we announced that we are removing the QR/Bar code support from Codename One and moving +it to an external library. We deprecated the API’s and starting from recent builds you will no longer be able to +use the builtin API. + +Zlib uses a native library that doesn’t support the new bitcode architecture expected in iOS. So once we removed +it Codename One compiled without a problem with bitcode support turned on. + +If you need support for QR/bar code scanning you need to migrate your code to use the new +[cn1-codescan](https://github.com/codenameone/cn1-codescan/) library instead. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Shai Almog** — May 25, 2016 at 5:54 pm ([permalink](https://www.codenameone.com/blog/ios-server-migration-plan.html#comment-22598)) + +> Shai Almog says: +> +> We just added ios.bitcode=false as an option to disable bitcode. If you are running into issues please try that build hint and let us know either way. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-server-migration-plan.html) + + +### **Gareth Murfin** — May 27, 2016 at 12:06 am ([permalink](https://www.codenameone.com/blog/ios-server-migration-plan.html#comment-21511)) + +> Gareth Murfin says: +> +> Will try this out Shai and let you know the results. Cheers, Gaz. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fios-server-migration-plan.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/issue-submission-guideline.md b/docs/website/content/blog/issue-submission-guideline.md new file mode 100644 index 0000000000..63c277cc92 --- /dev/null +++ b/docs/website/content/blog/issue-submission-guideline.md @@ -0,0 +1,140 @@ +--- +title: Issue Submission Guidelines +slug: issue-submission-guideline +url: /blog/issue-submission-guideline/ +original_url: https://www.codenameone.com/blog/issue-submission-guideline.html +aliases: +- /blog/issue-submission-guideline.html +date: '2016-04-26' +author: Shai Almog +--- + +![Header Image](/blog/issue-submission-guideline/how-to-use-the-codename-one-sources.jpg) + +One of the best things in running an open source project is the high quality issues, we don’t always respond +immediately and sometimes things get lost under our piles of work but we do appreciate the time you +take to file issues. + +We’d like to define some guidelines for issue submission, this will make our job easier in processing/assigning & +resolving issues as soon as possible. We don’t want this post to deter you from submitting an issue, it’s here to help. +If something is unclear in this post just go ahead and submit or ask a question in the comments section below. + +### Should I Submit an Issue? + +If you aren’t sure this is a bug we suggest googling and asking on [stackoverflow](http://stackoverflow.com/tags/codenameone) +or in the [discussion forum](/discussion-forum.html). + +If it’s a question, it probably doesn’t belong in the issue tracker and should go in the support channels. + +### Where to Submit an Issue? + +If you have an issue with any codenameone project they should all go into the +[main Codename One issue tracker](http://github.com/codenameone/CodenameOne/issues/). +This even includes issues with the [codenameone.com](https://www.codenameone.com/) website, the plugins & +even the cn1libs hosted under the codenameone user account. + +However, other cn1libs that are hosted under different user accounts should use their respective issue trackers! + +### Should I Edit the Issue or Just Post Comments? + +When we read an issue we usually start with the top description (the first comment). It needs to be as up to date +as possible and include the elements described in the next question. So please edit it with new information +related to the test case. + +Two things you should keep in mind: + + * Don’t edit the question in a way that removes/changes previous meaning. E.g. if you remove information from +the issue this will create a situation where comments might become unclear. Try to cleanup & elaborate without +distorting too much meaning + + * After editing is done post a comment. Editing doesn’t trigger a notification to people watching the project +and so developers might be unaware that you made an edit + +### What Should an Issue Include? + +The issue should obviously include a description of the problem and ideally a test case to reproduce it. +Make sure to highlight if the issue occurs on a device (include OS versions tested), simulator or both! + +Unless the issue is specifically related to the GUI builder we prefer the issue will be a small handcoded application coded +from the bare bones template. Ideally only the `start()` method should be included if that is possible. + +__ | The reason we prefer it this way is that we already have test case apps with the right provisioning/certificates etc. +in this way we can just paste your code directly into our existing test app and deploy +---|--- + +Source should be embedded using a backtick notation into the question followed by the word java on the first line e.g. + + + ````java + Your source goes here... + ```` + +Should produce Java syntax highlighted code in place. + +If you have a really complex project and there is no way to simplify it you can use either [gist](http://gist.github.com/) +or github itself and post a link to a project you committed. + +The reason we prefer this is that we can then browse the source quickly to find issues without downloading it and +instantly determine the right person to deal with a given issue. + +#### Screenshots & Videos + +Screenshots are often crucial pieces in describing some issues, if there is any visual aspect to your issue please include +a screenshot! + +You can grab a screenshot off of any device, please don’t use a camera to grab a device screenshot…​ + +__ | You can capture the screen on your iOS device using the Sleep/Wake and Home buttons. Press and hold +the Sleep/Wake button on the top or side of your iPhone, iPad, or iPod touch, then immediately press and release +the Home button. You can find the screenshot in your Photos app +---|--- + +__ | You can grab a screenshot of an Android device by holding the volume down button and the power button +---|--- + +Elements such as animations or artifacts require video you can grab a video of an iOS device using one +of the [techniques described here](http://www.apptamin.com/blog/capture-iphone-ipad-screen-video/). +Android 4.4 or newer requires the Android SDK to achieve a similar result using +[this technique](https://developer.android.com/tools/help/shell.html#screenrecord). +Using these techniques will allow a non-grainy video that’s easy to understand even for elaborate/refined issues. + +We recommend uploading the video to youtube as “unlisted” video and embedding the link into the issue. +This allows anyone to view the video almost instantly even on mobile while wading thru issues. This also + +#### Resources/Images + +Some issues require a resource file or image files. These can be added as attachments to the issue but we’d appreciate +if issues can be reproduced without such files if possible. + +### In Closing + +Issues are probably the best way most of us can do to help a project like Codename One or any other open +source project move forward. They are a great help and we really appreciate the effort that goes into them even +when they are not up to the standards above. + +However, if you follow the guidelines above it will make our work easier and it will make resolution of such +issues faster. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Jérémy MARQUER** — April 27, 2016 at 4:31 pm ([permalink](https://www.codenameone.com/blog/issue-submission-guideline.html#comment-22662)) + +> Jérémy MARQUER says: +> +> Hi, +> Can you help me with this issue please : [https://github.com/shannah/…]() +> I can’t build anymore for Android until library with andlib format is included in this cn1lib. Thanks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fissue-submission-guideline.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/its-full-of-stars-terse-commands.md b/docs/website/content/blog/its-full-of-stars-terse-commands.md new file mode 100644 index 0000000000..0b4d6dcfc6 --- /dev/null +++ b/docs/website/content/blog/its-full-of-stars-terse-commands.md @@ -0,0 +1,220 @@ +--- +title: It's Full Of Stars & Terse Commands +slug: its-full-of-stars-terse-commands +url: /blog/its-full-of-stars-terse-commands/ +original_url: https://www.codenameone.com/blog/its-full-of-stars-terse-commands.html +aliases: +- /blog/its-full-of-stars-terse-commands.html +date: '2016-02-23' +author: Shai Almog +--- + +![Header Image](/blog/its-full-of-stars-terse-commands/components-slider.png) + +A very common UI pattern is the 5 star ranking system. Up until recently we always had the same answer +when developers asked us how to implement it: “Use toggle buttons +([CheckBox](https://www.codenameone.com/javadoc/com/codename1/ui/CheckBox.html#createToggle-com.codename1.ui.Image-))”. + +This is still not a bad answer but we think there is a “better” simpler way to do this thru the +[Slider](https://www.codenameone.com/javadoc/com/codename1/ui/Slider.html) which was +effectively designed with this usage in mind. + +The best way to do that is to just create two images with all 5 stars full and with all 5 stars empty and assign +this to the `Slider`/`SliderFull` UIID’s. Keep in mind that you need to apply both to the selected and unselected +states of the UIID’s. + +__ | You can change the UIID of slider itself e.g. to something like “Stars” at which point the UIID’s will be +`Stars` & `StarsFull`. +---|--- + +This will allow your users to click/drag to select the number of stars. The code below uses the star material icon +to generate something like this on the fly without any resources. + +__ | We enclose the slider in a `FlowLayout` to prevent it from growing. This is because I chose the stars to be tiled +instead of aligned (like we could if we used an image). So if the component will grow it won’t have the right feel. +Enclosing the component in a `FlowLayout` is an old trick to prevent components from growing beyond their preferred +size. +---|--- + + + private void initStarRankStyle(Style s, Image star) { + s.setBackgroundType(Style.BACKGROUND_IMAGE_TILE_BOTH); + s.setBorder(Border.createEmpty()); + s.setBgImage(star); + s.setBgTransparency(0); + } + + private Slider createStarRankSlider() { + Slider starRank = new Slider(); + starRank.setEditable(true); + starRank.setMinValue(0); + starRank.setMaxValue(10); + Font fnt = Font.createTrueTypeFont("native:MainLight", "native:MainLight"). + derive(Display.getInstance().convertToPixels(5, true), Font.STYLE_PLAIN); + Style s = new Style(0xffff33, 0, fnt, (byte)0); + Image fullStar = FontImage.createMaterial(FontImage.MATERIAL_STAR, s).toImage(); + s.setOpacity(100); + s.setFgColor(0); + Image emptyStar = FontImage.createMaterial(FontImage.MATERIAL_STAR, s).toImage(); + initStarRankStyle(starRank.getSliderEmptySelectedStyle(), emptyStar); + initStarRankStyle(starRank.getSliderEmptyUnselectedStyle(), emptyStar); + initStarRankStyle(starRank.getSliderFullSelectedStyle(), fullStar); + initStarRankStyle(starRank.getSliderFullUnselectedStyle(), fullStar); + starRank.setPreferredSize(new Dimension(fullStar.getWidth() * 5, fullStar.getHeight())); + return starRank; + } + private void showStarPickingForm() { + Form hi = new Form("Star Slider", new BoxLayout(BoxLayout.Y_AXIS)); + hi.add(FlowLayout.encloseCenter(createStarRankSlider())); + hi.show(); + } + +In this code you will notice we allow selecting a value between 0 & 10 where 10 is really 5 stars. This allows us +to pick values like 4.5 stars and just divide the actual value. However, most ranking systems don’t allow a value +below 1 star. To solve this you can just use a `Label` to represent the first star and use a the `Slider` for the remaining +4 stars. In which case the values would be between 0 – 8. + +### Terse commands + +I love lambdas. I wasn’t a fan before they were introduced but they grew on me and made me a convert. + +One of the annoyances I had with Codename One was with using `Command` syntax which forced me to fallback +to pre-lambda code for practically everything as `Command` is a class and not a single method interface. This +bothered me enough to do something about it so now we have `ActionListener` versions of many `Command` API’s. + +These all redirect to the +[Command.create(String,Image,ActionListener)](https://www.codenameone.com/javadoc/com/codename1/ui/Command.html#create-java.lang.String-com.codename1.ui.Image-com.codename1.ui.events.ActionListener-) +method which effectively creates a `Command` with the given details for the given action listener. So instead +of writing code like this: + + + form.getToolbar().addToSideMenu(new Command("My Command") { + public void actionPerformed(ActionEvent ev) { + myCodeHere(); + } + }); + +I can write this: + + + form.getToolbar().addToSideMenu(Command.create("My Command", null, (ev) -> { + myCodeHere(); + })); + +And to make things even simpler I created helper methods that do that implicitly in `Toolbar` and `Form`: + + + form.getToolbar().addToSideMenu("My Command", null, (ev) -> { + myCodeHere(); + }); + +Notice that the version of this method that accepts a the action listener also returns the created `Command` instance +which might be useful if you want to do something with the command later on (e.g. remove it). So this should work: + + + Command cmd = form.getToolbar().addToSideMenu("My Command", null, (ev) -> { + myCodeHere(); + }); +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Diamond** — February 24, 2016 at 2:49 pm ([permalink](https://www.codenameone.com/blog/its-full-of-stars-terse-commands.html#comment-22227)) + +> Diamond says: +> +> Hi Shai, +> +> Please check this page, it’s not aligned. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fits-full-of-stars-terse-commands.html) + + +### **Shai Almog** — February 24, 2016 at 2:52 pm ([permalink](https://www.codenameone.com/blog/its-full-of-stars-terse-commands.html#comment-22727)) + +> Shai Almog says: +> +> Hi Diamond, +> I just played a bit with the UI for asciidoc conversion of blog posts. What browser/OS combination are you using? Can you provide a screenshot so I can see if we are seeing the same thing? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fits-full-of-stars-terse-commands.html) + + +### **Diamond** — February 24, 2016 at 5:50 pm ([permalink](https://www.codenameone.com/blog/its-full-of-stars-terse-commands.html#comment-22465)) + +> Diamond says: +> +> Chrome on Windows 10 machine. +> +> Here is the screenshot. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fits-full-of-stars-terse-commands.html) + + +### **Shai Almog** — February 24, 2016 at 6:39 pm ([permalink](https://www.codenameone.com/blog/its-full-of-stars-terse-commands.html#comment-22673)) + +> Shai Almog says: +> +> Gotcha, that’s a really wide screen. Looking into it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fits-full-of-stars-terse-commands.html) + + +### **Shai Almog** — February 25, 2016 at 7:25 pm ([permalink](https://www.codenameone.com/blog/its-full-of-stars-terse-commands.html#comment-22408)) + +> Shai Almog says: +> +> Just did an update, is it better? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fits-full-of-stars-terse-commands.html) + + +### **Diamond** — February 25, 2016 at 7:26 pm ([permalink](https://www.codenameone.com/blog/its-full-of-stars-terse-commands.html#comment-22500)) + +> Diamond says: +> +> Yes, it’s fixed now. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fits-full-of-stars-terse-commands.html) + + +### **Shai Almog** — December 20, 2016 at 4:43 am ([permalink](https://www.codenameone.com/blog/its-full-of-stars-terse-commands.html#comment-22867)) + +> Shai Almog says: +> +> Thanks! +> Just use getProgress() on the Slider component: [http://codenameone.com/java…]() +> Not the most intuitive method name for this case but we initially designed it as a progress indicator… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fits-full-of-stars-terse-commands.html) + + +### **safa** — April 29, 2017 at 10:53 pm ([permalink](https://www.codenameone.com/blog/its-full-of-stars-terse-commands.html#comment-23331)) + +> safa says: +> +> hello , how can i get and set the values of rating stars? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fits-full-of-stars-terse-commands.html) + + +### **Shai Almog** — April 30, 2017 at 4:14 am ([permalink](https://www.codenameone.com/blog/its-full-of-stars-terse-commands.html#comment-23482)) + +> Shai Almog says: +> +> The guy who asked this 4 months ago deleted his question but my answer is the same: +> Just use getProgress() on the Slider component: [http://codenameone.com/java]()… +> Not the most intuitive method name for this case but we initially designed it as a progress indicator… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fits-full-of-stars-terse-commands.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/its-in-the-bag.md b/docs/website/content/blog/its-in-the-bag.md new file mode 100644 index 0000000000..59a3b56c79 --- /dev/null +++ b/docs/website/content/blog/its-in-the-bag.md @@ -0,0 +1,102 @@ +--- +title: It's In The Bag +slug: its-in-the-bag +url: /blog/its-in-the-bag/ +original_url: https://www.codenameone.com/blog/its-in-the-bag.html +aliases: +- /blog/its-in-the-bag.html +date: '2013-08-18' +author: Shai Almog +--- + +![Header Image](/blog/its-in-the-bag/its-in-the-bag-1.png) + + + + +[ +![GridBagLayout Swing vs. Codename One](/blog/its-in-the-bag/its-in-the-bag-1.png) +](/img/blog/old_posts/its-in-the-bag-large-2.png) + + + +GridBag that is. So GridBagLayout is +[ +one of the most notorious of the layout managers in Java +](http://madbean.com/anim/totallygridbag/) +in fact for many developers it symbolizes the failure of the layout manager concept. That is the main reason why we never added it. + + +Last week I had a very interesting conversation with a very prominent Swing developer + +and he asked me whether we had gridbag support. I answered that we do not and repeated the regular “no one likes it” line, turns out he does like it and has a lot of Swing code that uses GridBag! + + + +Interesting… + + +Porting a Swing/AWT layout manager to Codename One is pretty close to trivial, there are very few things you need to actually change. + + + 1. +Codename One doesn’t have Insets, I added some support for them in order to port gridbag but components in Codename One have a Margin they need to consider instead of the insets (the padding is in the preferred size). + + 2. +AWT layout managers also synchronize a lot on the AWT thread. This is no longer necessary since Codename One is single threaded like Swing. + + 3. +Components are positioned relatively to container so the layout code can start at 0, 0 (otherwise it will be slightly offset). + +Other than those things its mostly just fixing method signatures and import statements which are slightly different. Pretty trivial stuff and GridBagLayout from project Harmony is now working on Codename One. + + + +So to show this off I +[ +took this code from the Java tutorial +](http://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html) +and ported it to Codename One, pretty easy stuff: + + + +* * * + +The code is almost the same although I did need to make some adaptations e.g. JButton to Button, add to addComponent and reverse the order of arguments to addComponent. Other than that it was pretty trivial. + + + +Now this stuff probably won’t make it into the GUI builder in the forseeable future, but if you are hellbent on GridBag or porting some Swing code this should be pretty convenient. Its also a great case study if you want to port some of your other favorite layout managers such as MiG or FormLayout. + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — August 19, 2013 at 11:51 pm ([permalink](https://www.codenameone.com/blog/its-in-the-bag.html#comment-21776)) + +> Anonymous says: +> +> I agree that GridBagLayout was hell to configure by hand, however I learned to like it more since the NetBeans team created their fancy customizer a few years ago… I wonder how easy/hard it would be to reuse it in CN1’s own designer ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fits-in-the-bag.html) + + +### **Anonymous** — September 5, 2013 at 3:35 pm ([permalink](https://www.codenameone.com/blog/its-in-the-bag.html#comment-21803)) + +> Anonymous says: +> +> Yeah, I used gridbag a lot. It might be painful, but sometimes it was the best thing to do. I tried some of the other replacements and they were even more difficult and were not hand modifiable. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fits-in-the-bag.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/j2me-feature-phones-nokia-devices.md b/docs/website/content/blog/j2me-feature-phones-nokia-devices.md new file mode 100644 index 0000000000..3ae8d326c6 --- /dev/null +++ b/docs/website/content/blog/j2me-feature-phones-nokia-devices.md @@ -0,0 +1,249 @@ +--- +title: J2ME, Feature Phones & Nokia Devices +slug: j2me-feature-phones-nokia-devices +url: /blog/j2me-feature-phones-nokia-devices/ +original_url: https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html +aliases: +- /blog/j2me-feature-phones-nokia-devices.html +date: '2013-04-23' +author: Shai Almog +--- + +![Header Image](/blog/j2me-feature-phones-nokia-devices/j2me-feature-phones-nokia-devices-1.png) + + + + +[ +![Picture](/blog/j2me-feature-phones-nokia-devices/j2me-feature-phones-nokia-devices-1.png) +](/img/blog/old_posts/j2me-feature-phones-nokia-devices-large-3.png) + +Is J2ME dead or dying? + + + +How many times have we heard this for the past 3 years or so? Sadly the answer is: Yes! + + + +Unfortunately there is no active owner for the J2ME standard and thus no new innovation around J2ME for quite some time (MIDP 2.0 came out in 2004, 3.0 never really materialized). Android is/was the biggest innovation since and became the unofficial successor to J2ME. + + + +Well, if J2ME is dead what about Feature Phones? Should we care about them? + +The answer is: Yes! very much so! + +Features Phones are still selling in millions and still beats Android sales in the developing world.Recently Nokia shipped the Asha series devices which are quite powerful and capable pieces of hardware, they are very impressive. Nokia’s revenue is driven mainly by the Feature Phone market. + +There is a real battle in the developing countries between Feature Phones and Android devices, Feature Phones are still cheaper and more efficient where Android has more/better content (apps & games). + +How long will it take Android to catch up? we will see… + +In the meantime there is money on the table and a real opportunity for developers to make some money (and gain loyal users who will migrate to Android or other platform at some point) + +* * * + + + + +[ +![Picture](/blog/j2me-feature-phones-nokia-devices/j2me-feature-phones-nokia-devices-2.png) +](/img/blog/old_posts/j2me-feature-phones-nokia-devices-large-4.png) + +To win over the competition or at least to maintain its dominate player position Nokia must bring new quality content to the devices, it’s not enough to ship cool new feature phones, the new phone needs to connect to facebook, twitter, gmail, whatsapp and have all the new cool games/apps Android has and more. + +So how should you write your apps for the cool new Nokia Feature Phone if J2ME is dead? Luckily there is an option Codename One ;-). + +In Codename One You have 1 Java API which is the same for J2ME, Android, iOS, Blackberry and Win8. + +Below are some of the J2ME highlights: + + 1. Facebook Connect – did you noticed there aren’t many social apps on OVI? + +There is a reason Facebook uses oauth2 which is a huge pain without a browser API, this is solved and working in Codename One. + 2. Java 5 features – You can use generics and other Java 5 features in your app and it will work on your J2ME/Blackberry devices. You don’t have to limit yourself to CLDC. + 3. Rich UI – If you know or knew LWUIT (Swing like API), well Codename One UI is effectively LWUIT 2.0. + 4. Built in Asha skins and themes + +The most important thing is the fact that your skills are not wasted on an old/dying J2ME API, by joining our growing community and writing the next amazing app your skills can target the emerging platforms of the present/future. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — April 24, 2013 at 5:09 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21864)) + +> Anonymous says: +> +> That is a good possibility to develop j2me functionalities/apps through codename one, but also i don’t think that j2me is really dying… +> +> Have a look: +> +> [http://www.oracle.com/techn…]() +> +> [http://www.netmarketshare.c…]([http://www.netmarketshare.com/operating-system-market-share.aspx?qprid=9&qpcustomb=1](http://www.netmarketshare.com/operating-system-market-share.aspx?qprid=9&qpcustomb=1)) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — April 24, 2013 at 6:51 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21743)) + +> Anonymous says: +> +> j2me is already dead, you would get laughed at by any serious developer if you told them you still programmed in it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — April 24, 2013 at 7:31 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21786)) + +> Anonymous says: +> +> but i would not tell them 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — April 24, 2013 at 7:39 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21781)) + +> Anonymous says: +> +> We actually agree with that, we try not to list it anywhere on our site because of that (even though we still support it). +> +> I recently had the pleasure to meet one of the guys working on the feature phone platform for Facebook (based on their Snaptu acquisition) and he surprised me by saying that they still see growth in the feature phone version… This is pretty amazing, I would have expected decline but this is apparently still to come. +> +> To be clear, I would never target J2ME as my main platform but if we can get there for almost free that could be interesting. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — April 24, 2013 at 7:39 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21855)) + +> Anonymous says: +> +> Just show the numbers and they will stop laughing, also, it is way easier to get a better spot for your app at Nokia OVI store than the others +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — April 24, 2013 at 9:37 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21906)) + +> Anonymous says: +> +> Hey everyone, +> +> Shai really cool read by the way. It’s funny how the situation changes from country to country, Where I live in, you still see lots and lots of people with Nokia s40 phones even though Android, iOS and Windows Phones are getting a whole lot more common. I think it’s great you guys support the J2ME through Codename One even if not to the level of the other platforms because it gives us as developers the possibility to reach an even bigger market without the effort of having to learn it or the obligation of targeting as a main platform. +> +> I think you guys are doing a marvelous job with Codename One and I really hope to see it grow and support a whole lot of different stuff there’s still left to explore. Keep up the great work! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — April 24, 2013 at 10:24 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21901)) + +> Anonymous says: +> +> Isn’t it a simple case of demand? Just because a technology is good, doesn’t mean it will last forever. If the majority of the market is no longer supporting or working with J2ME, then developers will disappear and products will disappear. Of course, as the article says, there is still a market for J2ME software, the market is just a fraction of what it used to be. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — April 24, 2013 at 12:34 pm ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21754)) + +> Anonymous says: +> +> Samsung is now prepared to compete with Nokia Asha in the feature phone market with the recent release of 4 new full touch devices, the Rex 60, 70, 80, and 90. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — May 1, 2013 at 6:54 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21893)) + +> Anonymous says: +> +> In this part of the world, Nigeria, j2me is still alive but whether it will remain or not is the question. +> +> Nokia and Tecno are making huge sales quarterly in Africa, with over 10 million sales in one quarter. +> +> My app got over 2000 downloads in few weeks of release to the Nokia Store, without any publicity. +> +> If Codenameone really wanna support Asha devices, I think they should implement some of the Asha specific APIs. +> +> I had to create a native app for my Nearest Locator mobile app in other to fully maximize the Asha LPS feature. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — May 16, 2013 at 9:22 pm ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21941)) + +> Anonymous says: +> +> Does Codename One support the new Asha platform in Asha 501? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — May 17, 2013 at 1:45 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21748)) + +> Anonymous says: +> +> Yes, it supports all asha series +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — September 26, 2013 at 6:58 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-24159)) + +> Anonymous says: +> +> its sad to know that j2me may soon go into oblivion. i love the m3g based 3d games which i think are simpler to make compared to open gl es which is quite popular now. I was hoping to release a good number of 3d apps based on m3g on j2me platform in Nigeria but i guess i’have to port to android os or IOS and i am not happy about that. I love m3g on j2me,i wish it was available on android or Ios instead of open gl es. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — October 9, 2013 at 11:32 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21989)) + +> Anonymous says: +> +> I wouldn’t say that with full confidence. Javascript wasn’t considered a serious language to develop except to make a website more interactive. Look at it now, it’s part of a serious platform tool to develop mobile apps that will allow a single source base to run on the two most popular devices, iOS and Android. +> +> Why is that? because it allows a single source base to run on multiple platforms. For any business int he industry, this is economical. Codename One offers the same leverage using J2ME SDK. So for those with the skills set already, this is a viable option to use when one is consulting or providing a mobile solution to a client. +> +> However, the risk is, how is J2ME being kept up to date. Who is maintaining the SDK to keep up with the moving technology. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — October 9, 2013 at 3:09 pm ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21762)) + +> Anonymous says: +> +> We don’t use the J2ME SDK. +> +> We use Java 5 (J2ME ends with JDK 1.4 subset) and we add a lot of features that don’t exist in J2ME (while still maintaining compatibility). I would not target J2ME alone but Codename One allows some developers to have their cake and eat it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + + +### **Anonymous** — May 29, 2014 at 6:41 am ([permalink](https://www.codenameone.com/blog/j2me-feature-phones-nokia-devices.html#comment-21782)) + +> Anonymous says: +> +> i want to be a developer and i think j2me sdk is the best app to start with i have on my tecno device(tecno t531) but i need to learn how to use it pls help me i know you are advanced programmers +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fj2me-feature-phones-nokia-devices.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/jailbreak-rooting-detection.md b/docs/website/content/blog/jailbreak-rooting-detection.md new file mode 100644 index 0000000000..64fa5882d0 --- /dev/null +++ b/docs/website/content/blog/jailbreak-rooting-detection.md @@ -0,0 +1,35 @@ +--- +title: Jailbreak/Rooting Detection +slug: jailbreak-rooting-detection +url: /blog/jailbreak-rooting-detection/ +original_url: https://www.codenameone.com/blog/jailbreak-rooting-detection.html +aliases: +- /blog/jailbreak-rooting-detection.html +date: '2017-01-23' +author: Shai Almog +--- + +![Header Image](/blog/jailbreak-rooting-detection/security.jpg) + +iOS & Android are walled gardens which is both a blessing and a curse. Looking at the bright side the walled garden aspect of locked down devices means the devices are more secure by nature. E.g. on a PC that was compromised I can detect the banking details of a user logging into a bank. But on a phone it would be much harder due to the deep process isolation. + +This isn’t true for jailbroken or rooted devices. In these devices security has been compromised often with good intentions (opening up the ecosystem) but it can also be used as a step in a serious attack on an application! + +For obvious reasons it’s really hard to accurately detect a jailbroken or rooted device but when possible if you have a high security app you might want to block the functionality or even raise a “silent alarm” in such a case. To detect this we are introducing a new method: + + + if(Display.getInstance().isJailbrokenDevice()) { + // probably jailbroken or rooted + } else { + // probably not + } + +Notice that this is all “probably”, we can’t be 100% sure as there are no official ways to detect that. That is why it’s crucial to encrypt everything and assume the device was compromised to begin with when dealing with very sensitive data. Still it’s worthwhile to use these API’s to make the life of an attacker just a little bit harder. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/jaring-and-libraries.md b/docs/website/content/blog/jaring-and-libraries.md new file mode 100644 index 0000000000..07a0f68994 --- /dev/null +++ b/docs/website/content/blog/jaring-and-libraries.md @@ -0,0 +1,244 @@ +--- +title: Jaring And Libraries +slug: jaring-and-libraries +url: /blog/jaring-and-libraries/ +original_url: https://www.codenameone.com/blog/jaring-and-libraries.html +aliases: +- /blog/jaring-and-libraries.html +date: '2013-07-21' +author: Shai Almog +--- + +![Header Image](/blog/jaring-and-libraries/jaring-and-libraries-1.png) + + + + + +![Classpath](/blog/jaring-and-libraries/jaring-and-libraries-1.png) + + +Don’t change the classpath + + +Support for JAR files in Codename One has been a source of confusion despite +[ +my previous post on the matter +](http://www.codenameone.com/3/post/2013/02/new-preliminary-library-support.html) +so its probably a good idea to revisit this subject again and clarify all the details. + + +The first source of confusion is changing the classpath. You should +** +NEVER +** +change + +the classpath or add an external JAR via the NetBeans/Eclipse classpath UI. The reasoning here is very simple, these IDE’s don’t package the JAR’s into the final executable and even if they did these JAR’s would probably use features unavailable or inappropriate for the device (e.g. java.io.File etc.). + +There are two use cases for wanting JAR’s and they both have very different solutions: + + 1. +Modularity – you want to divide your work to an external group. For this purpose use the cn1lib approach. + + 2. +Work with an existing JAR. For this you will need native interfaces. + + + +** +CN1Lib’s +** + + + +Lets start with modularity since its simpler and you can pretty much read +[ +my previous post on the matter +](http://www.codenameone.com/3/post/2013/02/new-preliminary-library-support.html) +which covers it pretty accurately. + +You can create a cn1lib in NetBeans although its really just a simple ant project with some special targets and a simple ant task for stubbing. In it you can write all your source code (including native code and libs as described below), when you build the file you will get a cn1lib file that you can place in your projects lib directory. + + +After a right click and refresh project libs completion will be available for you and you will be able to work as if the code was a part of your project. + +** + + +** + +** +Native JAR’s/Libs +** + + + + +For the second use case of existing JAR’s we have a more complex situation, the JAR could depend on features unavailable in Codename One and even if it doesn’t it might be compiled in a way that isn’t supported by Codename One. + + + +So taking an arbitrary JAR off the internet and expecting it to work on a mobile device is something that will probably never happen for any platform. + + + + + +Android supports using JAR’s since it is based around the java language + +, some JAR’s might even work on J2ME/RIM. To make use of this capability we can just place the JAR’s as is under the native/android directory (and respectively for J2ME/RIM). The way to go for iOS support would be to use .a files (iOS static libraries) which will get linked with your app in the same way that the JAR’s get linked. + + +The problem is that you still won’t be able to use the JAR (or .a file) from + +within your code, this JAR would be platform specific and you would need to write the “bridging” code to connect it to the native layer. To learn more about native interfaces I suggest reading the developer guide but basically what you need to do is define a native interface e.g.: + + + +* * * + +Here you can define the interface between your application (which can’t directly access the jar or .a file) and the native code which can. Now you can right click the interface select: Generate Native Access and go the native directory where you can edit the native code. + + +Notice that the jar will not appear in your IDE’s code completion and the code might be marked as “red” with error messages. That is because we can’t compile that code on the client, only on the server since we don’t have the native Android/iOS SDK’s installed on your PC or Mac (and even if we did, integrating so many difference pieces of software is problematic). + +** + +Final words + +** + + +Supporting + +an arbitrary JAR off the internet is something no one will ever be able to fully deliver on, although we do hope the cn1lib format will take off since it is pretty open and has many advantages over the standard jar format (proper javadoc based code completion is HUGE). + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — October 6, 2014 at 10:32 am ([permalink](https://www.codenameone.com/blog/jaring-and-libraries.html#comment-22246)) + +> Anonymous says: +> +> Hello. Sorry for noob question, but I not fully understand, Codename1 supported JNI libraries? I have Android project with few JNI dependencies (source code – C/C++) and would be great to port this project to WinPhone/Blackberry, but I don’t understand is this real with Codename1? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjaring-and-libraries.html) + + +### **Anonymous** — October 7, 2014 at 3:17 am ([permalink](https://www.codenameone.com/blog/jaring-and-libraries.html#comment-22259)) + +> Anonymous says: +> +> JNI makes sense on Android where you call from Java to C you can use JNI in the Android port by wrapping in an andlib. In iOS we support an Objective-C bridge not JNI so you can invoke your C code from objective-c. Blackberry has no ability to define native C code, in Windows Phone we support C# not C but you might be able to do something with unsafe although I haven’t tried this. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjaring-and-libraries.html) + + +### **Anonymous** — October 16, 2014 at 11:42 am ([permalink](https://www.codenameone.com/blog/jaring-and-libraries.html#comment-22164)) + +> Anonymous says: +> +> “Supporting an arbitrary JAR off the internet is something no one will ever be able to fully deliver on” +> +> I’m very skeptical about this claim after working with robovm, almost 99.99% of the time the arbitrary jar libraries that I downloaded from the internet and used worked out of the box. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjaring-and-libraries.html) + + +### **Anonymous** — October 16, 2014 at 10:33 pm ([permalink](https://www.codenameone.com/blog/jaring-and-libraries.html#comment-22282)) + +> Anonymous says: +> +> Besides the obvious problems of huge size and other problems generated in that approach there is a much bigger problem. JDK IS HUGE, we had a rooms full of QA engineers running TCK’s on our JVM ports which were CLDC grade at Sun, tonnes of tests for a WAY smaller API. OSS doesn’t test at that level. +> +> This isn’t some theoretical debate. java.io.File is problematic since the iOS filesystem structure is very limited on iOS. Sockets (hence the entire network stack) can’t be implemented correctly in iOS. It will work for you in the testing environment but when you see disconnects in the field know that there is a reason for that. +> +> This can be OK for some games to hack something together, but its not an option if you need something to be forward compatible and warranted. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjaring-and-libraries.html) + + +### **Anonymous** — October 18, 2014 at 7:19 am ([permalink](https://www.codenameone.com/blog/jaring-and-libraries.html#comment-21662)) + +> Anonymous says: +> +> the java.lang.*, java.util.*, etc in robovm are based on Android’s runtime, they don’t suffer from the size problems as in Java SE but still allows a lot of flexibility regarding the usage of third party libraries. I hope codenameone could learn something from robovm’s approach in using Java for IOS developement +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjaring-and-libraries.html) + + +### **Anonymous** — October 18, 2014 at 8:54 am ([permalink](https://www.codenameone.com/blog/jaring-and-libraries.html#comment-22176)) + +> Anonymous says: +> +> Android VM is just as big as JavaSE. In an Android device it takes up that space ONCE for all the apps. On iOS you need to package it with the app so its HUGE. +> +> I’ve spoken at length with Niklas at the last JavaOne and briefly in this one (we were both quite busy). I like him, hes very smart and a nice guy to boot. Unfortunately I think he picked a wrong and remarkably risky approach for building iOS apps. +> +> To understand why you need to understand that: +> +> works for me right now != works for all use cases always +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjaring-and-libraries.html) + + +### **Anonymous** — October 24, 2014 at 4:07 am ([permalink](https://www.codenameone.com/blog/jaring-and-libraries.html#comment-21926)) + +> Anonymous says: +> +> Thanks for your replies, +> +> packaging a run-time for each and every app is a bad idea. I agree. +> +> a better approach would be to have some sort of a separate “run-time app” that manages all the java apps. +> +> an analogy to this could be the python run-time app in Symbian. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjaring-and-libraries.html) + + +### **Anonymous** — October 24, 2014 at 10:02 am ([permalink](https://www.codenameone.com/blog/jaring-and-libraries.html#comment-22052)) + +> Anonymous says: +> +> Apple disallows that just like it disallows a JIT or downloadable code. +> +> Both RoboVM and us take a very similar approach with the difference that we took a far more conservative route. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjaring-and-libraries.html) + + +### **Anonymous** — November 24, 2014 at 6:16 pm ([permalink](https://www.codenameone.com/blog/jaring-and-libraries.html#comment-21927)) + +> Anonymous says: +> +> I think i can use codename one for my project, but I wonder if It’ll support some complex libraries like Picasso or retrofit… and as there is no iOS alternative for those libraries what can i do about it. If not i may try it anyway for less complex projects. Thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjaring-and-libraries.html) + + +### **Anonymous** — November 25, 2014 at 4:50 am ([permalink](https://www.codenameone.com/blog/jaring-and-libraries.html#comment-22309)) + +> Anonymous says: +> +> Both of these don’t make sense in Codename One since they are there to solve Android specific problems and use Android networking API’s (unavailable in Codename One). +> +> Picasso is redundant since we have URLImage which is even more seamless in its image handling builtin to the system e.g. [http://www.codenameone.com/…]() +> +> Retrofit is nice but if you have access to the server a more portable (and much faster) approach would be to use the webservice wizard [http://www.codenameone.com/…]([http://www.codenameone.com/how-do-i—access-remote-webservices-perform-operations-on-the-server.html](http://www.codenameone.com/how-do-i---access-remote-webservices-perform-operations-on-the-server.html)) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjaring-and-libraries.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/java-8-api-23-defaults.md b/docs/website/content/blog/java-8-api-23-defaults.md new file mode 100644 index 0000000000..0c9e65e7a3 --- /dev/null +++ b/docs/website/content/blog/java-8-api-23-defaults.md @@ -0,0 +1,50 @@ +--- +title: Java 8 & API 23 defaults +slug: java-8-api-23-defaults +url: /blog/java-8-api-23-defaults/ +original_url: https://www.codenameone.com/blog/java-8-api-23-defaults.html +aliases: +- /blog/java-8-api-23-defaults.html +date: '2016-08-29' +author: Shai Almog +--- + +![Header Image](/blog/java-8-api-23-defaults/marshmallow.png) + +One of the biggest changes we made in the past couple of years was the introduction of Java 8 language support features and making it the default target. We are now ready for the next step: removing compatibility for Java 5 targeted builds. + +Notice that this won’t break existing projects…​ They will compile with the retrolambda pipeline even if you set the build hint `java.version=5`. + +We are doing this so we can integrate Java 8 features into the core of the Codename One itself and make the implementation more efficient/easy. + +This change will go in this Friday, if you have old projects that you haven’t compiled in a while we would suggest testing them. + +### Android API 23 Default + +We mentioned [Android permissions](/blog/switching-on-android-marshmallow-permission-prompts.html) a while back. We are now switching to API level 23 by default as this makes more sense moving forward. + +Unlike the language change you could still revert this change manually by defining `android.targetSDKVersion=21`. Notice that this is a short term solution as our goal is to keep up with the current Android release cycle. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Simone Peirani** — September 7, 2016 at 7:16 am ([permalink](https://www.codenameone.com/blog/java-8-api-23-defaults.html#comment-23032)) + +> Simone Peirani says: +> +> Hi, +> I noticed an issue with BTDemo on Android 6.0.1 device (with API 23 in build hints). To get works the App the user should go under settings –> App – – > BTDemo –> Authorizations, and manually enable the position authorization. +> By setting API 21 under build hints, BTDemo perfectly works instead. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-8-api-23-defaults.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/java-8-support.md b/docs/website/content/blog/java-8-support.md new file mode 100644 index 0000000000..d35706d549 --- /dev/null +++ b/docs/website/content/blog/java-8-support.md @@ -0,0 +1,181 @@ +--- +title: Java 8 Support +slug: java-8-support +url: /blog/java-8-support/ +original_url: https://www.codenameone.com/blog/java-8-support.html +aliases: +- /blog/java-8-support.html +date: '2015-07-05' +author: Shai Almog +--- + +![Header Image](/blog/java-8-support/java-8-lambada.png) + +When we introduced Codename One initially we limited the API to CLDC level which is roughly a subset of Java 1.3, we then +added support for a subset of Java 5 and we are now adding Java 8 language features! +Thanks to some work from Steve and the great work done by the guys from the +[Retro Lambda](https://github.com/orfjackal/retrolambda/) project we were able to add compatibility +to the major Java 8 features, most notably lambda expressions. This is highly experimental and some features +might not work but so far it seems things are functioning rather smoothly. + +Note that this feature will only be available with the next plugin update and isn’t online right now… +The main motivation for doing this is in reducing a lot of the boilerplate code you would normally get when writing +Codename One code, e.g. currently we write something like: + + + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Dialog.show("Event Happened", "You pressed a button", "OK", null); + } + }); + +Whereas lambdas allow us to write this: + + + button.addActionListener((e) -> { + Dialog.show("Event Happened", "You pressed a button", "OK", null); + }); + +Technically both are practically identical! +This can be applied across the board e.g.: + + + Display.getInstance().callSerially(() -> { + // this code executes on the EDT.... + }); + +This won’t be the default until we are confident that this is stable enough, with an upcoming plugin update +you will have an option to create a Java 8 project instead of a Java 5 project. You could also convert existing +projects to Java 8 but that will require some effort: + + 1. Make sure you have Java 8 installed and that your IDE is running under Java 8 + 2. Change all “source” and “target” values for Javac calls in build.xml from 1.5 to 1.8. + 3. Update the IDE build settings for the project (in the project properties menu) to use Java 8 source level + 4. Add the build hint `java.version=8` + 5. Update CLDC11.jar to the latest version using the Update Client Libs button in the project preferences + +The post mostly covered lambdas but other newer Java features such as String based switch cases (from Java 7) +try with resources etc. should work just fine however we didn’t do enough tests for the various features on all the +platforms (hence the beta moniker). +Try with resources is pretty cool e.g. you can do something like: + + + try(InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/myFile")) { + // work with file + } catch(IOException err) { + Dialog.show("Error", "Exception accessing the resource", "OK", null); + } + + +Which doesn’t seem like much until you realize that this really replaced this code: + + + InputStream is = null; + try { + is = Display.getInstance().getResourceAsStream(getClass(), "/myFile"); + // work with file + } catch(IOException err) { + Dialog.show("Error", "Exception accessing the resource", "OK", null); + } finally { + if(is != null) { + try { + is.close(); + } catch(IOException err) {} + } + } + + +Just to be fair, this code can be slightly more concise in the finalizer block with Codename One’s `Util.cleanup(is)` method… + +One feature of Java 8 that isn’t supported at the moment is [streams](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html). +While they would be nice to have they probably won’t be as helpful as the other +features in a mobile environment and won’t provide performance benefits in these cases. We might add them +at a future date if there is demand for that. + +Notice that Java 8 support was mostly tested with Android, iOS & the desktop port. It should work well with most modern ports but might have issues +in platforms such as J2ME/RIM where even the Java 5 compatibility is flaky. +The image in the title of this post is from this [Takipi blog](http://blog.takipi.com/the-dark-side-of-lambda-expressions-in-java-8/) which +is pretty relevant to the subject of this post. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **James Hastings** — July 6, 2015 at 5:19 pm ([permalink](https://www.codenameone.com/blog/java-8-support.html#comment-22329)) + +> James Hastings says: +> +> This is great news. What about the localdate class? I have a program I wrote that uses a bunch of localdate functionality that I wanted to port into a mobile app. Refactoring everything to Calendar and Date objects has kept this on the backburner for me. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-8-support.html) + + +### **Shai Almog** — July 7, 2015 at 5:47 am ([permalink](https://www.codenameone.com/blog/java-8-support.html#comment-22434)) + +> Shai Almog says: +> +> Thanks. +> That isn’t supported at the moment and probably won’t be around in the immediate future. The main hurdle is compatibility to existing platforms so we are walking on eggshells here trying to minimize the impact of the core libraries. +> +> I feel your pain, every Java developer who dealt with dates in any way hates Calendar/Date. I am looking forward to migrating to something decent, but that might be a while. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-8-support.html) + + +### **Codrut Gusoi** — July 7, 2015 at 6:39 pm ([permalink](https://www.codenameone.com/blog/java-8-support.html#comment-21543)) + +> Codrut Gusoi says: +> +> Yay lambdas! +> Brace yourselves, assertException() is coming… at least when I will have time for a pull request. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-8-support.html) + + +### **Sanny Sanoff** — August 2, 2015 at 10:52 am ([permalink](https://www.codenameone.com/blog/java-8-support.html#comment-22356)) + +> Sanny Sanoff says: +> +> Will they (lambdas) work on Android, too? How do you implement this feature if you just pass user java to dalvik? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-8-support.html) + + +### **Shai Almog** — August 4, 2015 at 4:27 am ([permalink](https://www.codenameone.com/blog/java-8-support.html#comment-22150)) + +> Shai Almog says: +> +> Yes. +> It works on all platforms even J2ME since it uses retrolambda on the server before the main processing of the bytecode. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-8-support.html) + + +### **Martin Grajcar** — November 27, 2019 at 2:21 pm ([permalink](https://www.codenameone.com/blog/java-8-support.html#comment-24272)) + +> [Martin Grajcar](https://lh6.googleusercontent.com/-gclegbxVkVE/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3reP0qIwi57AHP6gC6BhvXA4p34zZA/photo.jpg) says: +> +> Unlike inner classes, lambdas don’t capture the enclosing class…. I just find out that I’m storing quite a few lambdas generated in forms, which must not retain the reference to the enclosing form. +> +> Do retrolambdas retain the reference to the enclosing class? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-8-support.html) + + +### **Shai Almog** — November 28, 2019 at 2:25 am ([permalink](https://www.codenameone.com/blog/java-8-support.html#comment-24271)) + +> Shai Almog says: +> +> Retrolambda translates Java 8 lambdas to inner classes internally. Lambdas use `this` as a reference to their surrounding class so they have a reference to their parent just like non-static inner classes. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-8-support.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/java-8-switch-new-preferences-demo-structure.md b/docs/website/content/blog/java-8-switch-new-preferences-demo-structure.md new file mode 100644 index 0000000000..6d1d13246c --- /dev/null +++ b/docs/website/content/blog/java-8-switch-new-preferences-demo-structure.md @@ -0,0 +1,90 @@ +--- +title: Java 8 Switch, New Preferences & Demo Structure +slug: java-8-switch-new-preferences-demo-structure +url: /blog/java-8-switch-new-preferences-demo-structure/ +original_url: https://www.codenameone.com/blog/java-8-switch-new-preferences-demo-structure.html +aliases: +- /blog/java-8-switch-new-preferences-demo-structure.html +date: '2016-05-08' +author: Shai Almog +--- + +![Header Image](/blog/java-8-switch-new-preferences-demo-structure/java-8-lambada.png) + +With the 3.4 release we discussed the process of modernizing the demos and also mention that we would +continue the trend of building Codename One on top of itself. We now have a rough outline of what we are +going to do possibly starting with the next plugin update. + +### Java 8 Switch + +New builds will use Java 8 by default for all projects. In the past we needed you to define the build hint +`java.version=8` and if you left it out we defaulted to `java.version=5`. + +With the this will now be the exact opposite where the default will assume Java 8 unless you are using +versioned builds. + +This is a part of a wider switch that we will carry into the IDE plugin and into the Codename One libraries. +The Codename One plugins will require Java 8 to install starting with the next update, we’re not sure if there +is a way to enforce this with the IDE dependencies but we will start assuming that Java 8 + +### New Preferences UI + +One of the hard things about maintaining the plugin for 3 platforms is the preferences UI which we need to +update across all platforms. With new changes coming up to the Windows UWP build we will need to make +changes to the preferences and carrying them to all IDE’s might be challenging. + +So we are focusing around one UI which is the one we introduced with the [IntelliJ IDEA plugin](/blog/a-new-idea.html). +This UI is written in Codename One and solves a lot of bugs in the old preferences UI’s both in Eclipse & NetBeans. + +![Preferences UI written in Codename One](/blog/java-8-switch-new-preferences-demo-structure/a-new-idea-preferences.png) + +Figure 1. Preferences UI written in Codename One + +This will allow us to map functionality to UI preferences more smoothly as we move Codename One forward. + +#### Old Preferences + +For now we won’t remove the old preferences UI as the new interface might still be unstable. However, we will +post a notice that the UI is deprecated and will remove it in a future iteration. + +You will find the new preferences option under the Codename One section in an upcoming plugin update. + +### New Demo Structure + +We decided to move the demos to separate repositories and retire the monolithic +[codenameone-demos](https://github.com/codenameone/codenameone-demos) repository. +This will allow us to be more nimble and will also simplify the process of working with these demos. + +We will recreate the individual demos one by one in separate repositories and integrate them into the +new plugin implementation. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Maaike Z** — May 10, 2016 at 9:07 am ([permalink](https://www.codenameone.com/blog/java-8-switch-new-preferences-demo-structure.html#comment-21510)) + +> Can we also use the Java 8 Date/Time functions or is this just for running the plugin etc? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-8-switch-new-preferences-demo-structure.html) + + +### **Shai Almog** — May 11, 2016 at 5:40 am ([permalink](https://www.codenameone.com/blog/java-8-switch-new-preferences-demo-structure.html#comment-22832)) + +> Shai Almog says: +> +> No. This applies to the plugin and the default behavior which uses the current Java 8 retrolambda based support. +> +> There is an open source implementation of JSR 310 (date time) which we could possibly add (I already filed an RFE on that a while back) but I’m not sure how practical it is to add that. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-8-switch-new-preferences-demo-structure.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/java-developers-can-finally-target-windows-uwp.md b/docs/website/content/blog/java-developers-can-finally-target-windows-uwp.md new file mode 100644 index 0000000000..068d4611f8 --- /dev/null +++ b/docs/website/content/blog/java-developers-can-finally-target-windows-uwp.md @@ -0,0 +1,204 @@ +--- +title: Java Developers can FINALLY Target Windows UWP +slug: java-developers-can-finally-target-windows-uwp +url: /blog/java-developers-can-finally-target-windows-uwp/ +original_url: https://www.codenameone.com/blog/java-developers-can-finally-target-windows-uwp.html +aliases: +- /blog/java-developers-can-finally-target-windows-uwp.html +date: '2016-06-11' +author: Shai Almog +--- + +![Header Image](/blog/java-developers-can-finally-target-windows-uwp/universal-windows-apps_thumb.jpg) + +After many months of work and effort put in by all of us but especially by [Steve Hannah](http://twitter.com/shannah78) and +[Fabrício Carvalho Cabeça](https://twitter.com/ravnos_kun) we are finally live with the Windows Universal Platform (AKA UWP) +native build target! +As far as I know Codename One is the only native option for Java developers to build native Windows UWP apps. + +__ | Notice that this target is still in technology preview stage! Please report any issue you run into +---|--- + +Besides the effort of building the Codename One port with everything it entails (including newer build servers) +we also leveraged the ambitious [iKVM](http://www.ikvm.net) project which we had to modify extensively with +the help of some community members specifically [Eugene](https://twitter.com/Geraschenco) who proved very +helpful during this work! + +(I hope I didn’t forget anyone, I didn’t take an active role in this port and I might have missed someone if so please +accept my apologies). + +The whole source of this port as well as our changes to iKVM are available in [our git repository](http://github.com/codenameone/CodenameOne/). + +### What does this Mean? + +As of May Windows 10 is installed on 300 million PC’s and devices making it a significant platform and appstore. +Microsoft has traditionally been quite strong in the enterprise and the ability to sell into that market thru it’s +appstore (with the success of the Surface tablet line) is valuable. + +Microsoft has standardized on the Universal Windows Platform which effectively “reinvents” Windows as +a single platform on all supported devices. In a way this is very much like Java’s Write Once Run Anywhere +for the Windows ecosystem (mobile, tablets, xbox, desktops etc.). + +Windows UWP apps can be sold thru the Microsoft appstore which is currently growing as users are still +adopting Windows 10. + +#### Building an App + +You don’t need to make any change to your app to run it on a Windows 10 device/computer. Notice that you +will need a certificate file to ship such an app, we are still working on instructions to generate such a certificate +in a simple way but you can configure a license file in the new Codename One settings UI under the +Windows UWP settings. + +__ | This is currently optional, you can send a build without configuring a certificate to test this on your local machine +---|--- + +![Open the new Codename One preferences options in the right click for the project](/blog/java-developers-can-finally-target-windows-uwp/new-codenameone-settings.png) + +Figure 1. Open the new Codename One preferences options in the right click of the project + +![Scroll down using swipe and click the UWP section](/blog/java-developers-can-finally-target-windows-uwp/uwp-settings-section.png) + +Figure 2. Scroll down using swipe and click the UWP section + +![You can now set a certficiate file and password for signing a universal app](/blog/java-developers-can-finally-target-windows-uwp/uwp-settings.png) + +Figure 3. You can now set a certficiate file and password for signing a universal app + +To actually build the native app you can just right click and select the Windows UWP target, don’t be confused +with the two other options for desktop & the old Windows Phone support…​ + +![The new Windows UWP target](/blog/java-developers-can-finally-target-windows-uwp/windows-uwp-target.png) + +Figure 4. The new Windows UWP target + +Installing the build on your machine requires Windows 10 (obviously) but also requires development mode indicating +that you can “sideload” applications. We need to writeup our own documentation on how to do this but +for now check out +[this well written guide](https://support.hockeyapp.net/kb/client-integration-windows-and-windows-phone/how-to-sideload-uwp-applications#3-install-application). + +Once you do that your app can run on your machine and we should be able to submit such apps to the Windows +store: + +![Hello world app running on a Windows 10 laptop](/blog/java-developers-can-finally-target-windows-uwp/windows-app-running.png) + +Figure 5. Hello world app running on a Windows 10 laptop + +### What’s Next? + +The next set of steps depend on you. We will try to get apps into the Windows Store in order to complete the process +but we will consider this port production grade only when significant apps start shipping to the Windows Store. + +So we need bug reports and demand from you in order to bring this to that coveted production grade status…​ + +#### Future of Windows Desktop Port + +You will also notice, UWP allows building Windows desktop apps which overlaps with the Windows Desktop +build target that is currently limited to pro subscribers. + +There is still some value in the Windows desktop build in the sense that it’s really a Java SE application with the +full power of the JRE behind it. If you need that and compatibility to older versions of Windows this can be quite +powerful…​ + +However, if you are interested in a smaller native binary and can live with Windows 10 or newer as the baseline +I’d go for the new port as it should provide a superior native experience with a smaller footprint. + +For now we will keep supporting the Windows desktop target and have no plans of removing/deprecating it. + +### Build Hints + +__ | This section was added on June 14th and was missing from the original post…​ +---|--- + +By default debug builds are sent for Windows UWP builds, those default to using x64 architecture only to keep +the size small. When you send release builds you will receive a proper universal binary. + +To toggle these modes we added two build hints: + +`uwp.buildType` which can be either `debug` (the default) or `release`. + +`uwp.platforms` which defaults to `x64` on debug builds but can be set to `x64|x86|ARM` for universal builds. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — June 12, 2016 at 9:26 pm ([permalink](https://www.codenameone.com/blog/java-developers-can-finally-target-windows-uwp.html#comment-22469)) + +> This sounds really good. I don’t have much to do with the Windows eco-system, so if I want to try this, I’m guessing any recent Windows mobile should run this, or is there some specific version (of the seemingly ever changing) Windows mobile platform I need to look for ? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-developers-can-finally-target-windows-uwp.html) + + +### **Shai Almog** — June 13, 2016 at 3:53 am ([permalink](https://www.codenameone.com/blog/java-developers-can-finally-target-windows-uwp.html#comment-22731)) + +> It requires a device that’s running windows 10 and some of the older devices won’t get that upgrade. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-developers-can-finally-target-windows-uwp.html) + + +### **Chibuike Mba** — June 13, 2016 at 7:40 am ([permalink](https://www.codenameone.com/blog/java-developers-can-finally-target-windows-uwp.html#comment-22587)) + +> WOW!!! CodenameOne rocks, one stone (code base) to kill(target) all the birds(platforms) in the air(out there). Am loving it. Will surely try it in the next version of our app [http://ozioma.net](). Great job guys. 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-developers-can-finally-target-windows-uwp.html) + + +### **Lukman Javalove Idealist Jaji** — June 13, 2016 at 1:20 pm ([permalink](https://www.codenameone.com/blog/java-developers-can-finally-target-windows-uwp.html#comment-22771)) + +> I am over the moon with this!!!!!!!!! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-developers-can-finally-target-windows-uwp.html) + + +### **Ben A** — August 8, 2016 at 8:49 pm ([permalink](https://www.codenameone.com/blog/java-developers-can-finally-target-windows-uwp.html#comment-22711)) + +> Good news for Java devs +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-developers-can-finally-target-windows-uwp.html) + + +### **Teguh Kusuma** — September 5, 2016 at 4:24 pm ([permalink](https://www.codenameone.com/blog/java-developers-can-finally-target-windows-uwp.html#comment-22707)) + +> Teguh Kusuma says: +> +> Is it free for beginner developer? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-developers-can-finally-target-windows-uwp.html) + + +### **Shai Almog** — September 6, 2016 at 3:54 am ([permalink](https://www.codenameone.com/blog/java-developers-can-finally-target-windows-uwp.html#comment-22915)) + +> Shai Almog says: +> +> It is available to all subscription levels including the free level. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-developers-can-finally-target-windows-uwp.html) + + +### **Cristian Romascu** — September 29, 2016 at 5:51 am ([permalink](https://www.codenameone.com/blog/java-developers-can-finally-target-windows-uwp.html#comment-23034)) + +> Cristian Romascu says: +> +> Hello, i have 3 already made Java apps (using nothing but Java SE), can i convert them to UWP using Codename One? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-developers-can-finally-target-windows-uwp.html) + + +### **Shai Almog** — September 30, 2016 at 6:48 am ([permalink](https://www.codenameone.com/blog/java-developers-can-finally-target-windows-uwp.html#comment-23063)) + +> Shai Almog says: +> +> No. Codename One supports a subset of Java SE and our own UI API which is more portable than anything available in JavaSE. +> OTOH you will gain for your effort the portability to iOS, Android, UWP, JavaScript (with threads etc.) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-developers-can-finally-target-windows-uwp.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/java-is-superior-to-react-native-in-practically-every-way.md b/docs/website/content/blog/java-is-superior-to-react-native-in-practically-every-way.md new file mode 100644 index 0000000000..312502c2f0 --- /dev/null +++ b/docs/website/content/blog/java-is-superior-to-react-native-in-practically-every-way.md @@ -0,0 +1,1339 @@ +--- +title: Java is Superior To React Native In Practically Every Way +slug: java-is-superior-to-react-native-in-practically-every-way +url: /blog/java-is-superior-to-react-native-in-practically-every-way/ +original_url: https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html +aliases: +- /blog/java-is-superior-to-react-native-in-practically-every-way.html +date: '2015-11-01' +author: Shai Almog +--- + +![Header Image](/blog/java-is-superior-to-react-native-in-practically-every-way/react-demo.png) + +I got into a discussion with a colleague on the Java vs. JavaScript subject, which is a problematic subject to +begin with. He then mentioned how great React Native is, I decided I have to look into it and maybe grab +some ideas for Codename One. + +There are some nice ideas there, but none of them is revolutionary or exceptional and most of them are pretty +old news for Codename One developers running in Java 8. + +One thing I did like was how short the [React demo code ](https://facebook.github.io/react-native/docs/tutorial.html#final-source-code)seemed to be, so I ported it to Codename One and ended up with roughly the same amount of code and arguably better/simpler code! Check out the full listing at the end of the article or in the github project [here](https://github.com/codenameone/codenameone-demos/tree/master/ReactDemo), but lets first review why the Java code is “better”. + +### Synchronous Execution + +JavaScript fans hate this but its still a fact that synchronous code is simpler to read, follow and debug. E.g. this +is the React Native version of the code that fetches the data: + + + fetchData: function() { + fetch(REQUEST_URL) + .then((response) => response.json()) + .then((responseData) => { + this.setState({ + dataSource: this.state.dataSource.cloneWithRows(responseData.movies), + loaded: true, + }); + }) + .done(); + }, + +I have well over 20 years of professional programming experience and this is still hard to follow. Apparently if +`done()` is omitted you won’t get any error handling? + +Its weird and error prone. I feel like a lot of code is hidden behind this which makes the terseness more +confusing than simplifying (kind of like following a political debate thru Twitter). + +To me our code is **way** simpler: + + + react.add(BorderLayout.CENTER, new InfiniteContainer() { + public Component[] fetchComponents(int index, int amount) { + try { + Collection data = (Collection)ConnectionRequest.fetchJSON(REQUEST_URL).get("movies"); + Component[] response = new Component[data.size()]; + int offset = 0; + for(Object movie : data) { + response[offset] = createMovieEntry(Result.fromContent((Map)movie)); + offset++; + } + return response; + } catch(IOException err) { + Dialog.show("Error", "Error during connection: " + err, "OK", null); + } + return null; + } + }); + +Notice that this isn’t the exact equivalent of the code above as we also create components, add them to the UI +and handle the resulting error! + +A more fair comparison would be: + + + try { + Collection data = (Collection)ConnectionRequest.fetchJSON(REQUEST_URL).get("movies"); + ... + } catch(IOException err) { + ... + } + +That’s effectively one line of code that could even be shorter after which we have the result… No flow, no callback! + +Developers often pour hate on the Java checked exceptions feature and I have to agree that they are sometimes painful. + +(f’ing `InterruptedException` is stupid) but this is a great example of why checked exceptions matter. + +We MUST handle errors properly and we can’t just ignore it until our code reaches production with this +lovely “TODO” comment that no one bothered reading. + +### One Language – Less Code + +The listings seem roughly equivalent in size but you will notice the react code ignores the native platform +specific code when dealing with the JavaScript code. Our listing is all encompassing, no additional code is needed +and no further boilerplate, projects etc. + +React Native takes this even further by mixing tags with the JavaScript code effectively mixing declarative code into +the regular flow. Yes it shortens the code, but also removes a huge part of the value of declarative programming +which is the separation of responsibilities. + +### Reload == Apply Code Changes + +React Native can be debugged by reloading which is there to help when working with the **awful** Android emulator. + +Luckily Codename One doesn’t need that emulator, you also don’t need to restart your app to reload compiled changes… E.g. in NetBeans just use “Apply Code Changes” in the debugger and your changes are instantly mirrored into a running app. + +### Scripting Languages Are Problematic “On Device” + +This isn’t quite a “React Native” specific rant, its related to all tools packaging JavaScript in the app bundle. +Scripting languages are great for the web, they are like “duct tape”. Show me a hacker who doesn’t LOVE duct tape! + +The temptation to ship an app built with such duct tape is big, but unlike the web where you can just fix that “weird undefined” bug in production by deploying a new update. With apps you need to go thru Apples approval process… This means production bugs that stay while you watch your rating drop. + +Yes, unit tests, lint and a lot of other solutions are supposed to catch those things but when you use a modern IDE and it detects potential null inference thanks to the strict language syntax its pretty amazing! + +E.g. a great example for JavaScripts over simplification of problems would be in code like this: + + + function reduce(var a) { + if(...) { + a = a - 1; + } else { + a = a + 1; + } + } + +If this was Java code we could tell exactly what would happen here… In JavaScript this isn’t quite the case! + +Lets assume that due to a bug a was somehow a string that is `"11"` as long as the condition is true (which might be the case in all test cases) this will act like a number. E.g. `a` will become `"10"`. + +But in production if the condition becomes false for some reason `a` would become `"111"`. + +If `a` represents something of value (e.g. debt, credit etc.) having an app with this bug in the store +could be really painful. + +### Environment + +React native uses the native development environments which means it needs a Mac for iOS development. + +It also means you do part of the work in the Android IDE, part of it in Xcode and the JavaScript work using a +text editor. + +Its amazing to me that developers are willing to throw away 30 years of IDE evolution for some syntactic +candy??? + +Are we that traumatized by Eclipse? + +Todays IDE’s are amazing and the fact you can track/debug your entire code via a single IDE is invaluable. + +The ability we have as a team to instantly see who used what and for what purpose is astounding, I can’t fathom how something like this can be used by a team of more than 2 people especially in a distributed workforce. + +### What I Liked About JavaScript + +The one thing I really like about working with JavaScript is the ease of working with JSON, while in the code below I reduced it significantly almost to the same size it’s still not as elegant. + +I’m still not a fan of duck typing or scripting languages but I’d really like to get something like property objects into Codename One and improve the integrated parsing. + +### Final Word + +One of the problems I find with terse programming is that people use it to hide basic concepts so too much happens in an “unspoken” way. This makes terse code as easy to read as a Tweet, unfortunately if you need to express even a moderately complex idea Twitter just doesn’t cut it and that’s a big problem with some of these API’s. + +React native has its fans, after all its probably better than PhoneGap which has its own set of limitations. But its +still a limited concept standing on the chicken legs of a scripting infrastructure. It has no real advantage when +compared to Codename One and has some obvious potential issues. + +### Java Listing + + + public class ReactDemo { + private static final String REQUEST_URL = "https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json"; + private Form current; + private EncodedImage placeholder; + + public void init(Object context) { + UIManager.initFirstTheme("/theme"); + } + + public void start() { + if(current != null){ + current.show(); + return; + } + placeholder = EncodedImage.createFromImage(Image.createImage(53, 81, 0), false); + Form react = new Form("React Demo", new BorderLayout()); + react.add(BorderLayout.CENTER, new InfiniteContainer() { + public Component[] fetchComponents(int index, int amount) { + try { + Collection data = (Collection)ConnectionRequest.fetchJSON(REQUEST_URL).get("movies"); + Component[] response = new Component[data.size()]; + int offset = 0; + for(Object movie : data) { + response[offset] = createMovieEntry(Result.fromContent((Map)movie)); + offset++; + } + return response; + } catch(IOException err) { + Dialog.show("Error", "Error during connection: " + err, "OK", null); + } + return null; + } + }); + react.show(); + } + + Component createMovieEntry(Result data) { + Container entry = BorderLayout.center( + BoxLayout.encloseY( + new SpanLabel(data.getAsString("title"), "Line1"), + new Label(data.getAsString("year"), "Line2"))). + add(BorderLayout.WEST, + URLImage.createToStorage(placeholder, data.getAsString("id"), + data.getAsString("posters/thumbnail"))); + return entry; + } + + public void stop() { + current = Display.getInstance().getCurrent(); + } + + public void destroy() { + } + } + +# Write Once, Run Anywhere. + +## Truly native cross-platform app development with Java or Kotlin for iOS, Android & Web. + +[ Get Started ](https://codenameone.com/getting-started.html) + +[ Why Codename one? ](https://codenameone.com/introduction.html) +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **bryan** — November 2, 2015 at 10:20 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22520)) + +> bryan says: +> +> I think you’ll need to be wearing your flame proof suit for a while – the Javascript guys always seem to take great exception to anyone dissing their baby. +> +> What you say about throwing away 30 years of IDE development is so true. I came across this [http://www.fse.guru/how-to-…]() the other day, and I thought to myself, back the day you could use Delphi, say, to develop a desktop app, and now to develop a web app you apparently need a 1001 bits of stuff, to create something that in almost every way is inferior to a desktop app. Weird. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — November 3, 2015 at 4:27 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22243)) + +> Shai Almog says: +> +> They REALLY hate me on Reddit 😉 +> +> I can take it, otherwise I wouldn’t have written it. +> +> That’s part of why we started Codename One, it seems innovation in this space is busy taking us backwards. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **oojr** — November 7, 2015 at 10:15 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22504)) + +> oojr says: +> +> ES7 async functions is coming next year and would make the code look even better, Javascript is shaping up to be “The Next Big Language” [https://jakearchibald.com/2…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — November 8, 2015 at 4:23 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22279)) + +> Shai Almog says: +> +> Its been brought to my attention that JavaScript fans can’t read my code and misunderstand me when I say that the code is sync… +> +> What I mean is that the code “looks” synchronous but really works like async code by running on the event dispatch thread and yet allowing for events etc. to still process seamlessly. That’s a pretty neat trick called invokeAndBlock: +> +> [http://www.codenameone.com/…]() +> +> [http://www.codenameone.com/…]() +> +> I think JavaScript has its place as an important language, but even huge JavaScript fans find it hard to create large maintainable projects in it. The question of where the line passes where you probably should switch to a more “strict” language like Java (Scala if you prefer a more dynamic language etc.) is a matter of personal choice. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **oojr** — November 10, 2015 at 4:04 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22358)) + +> oojr says: +> +> I went into a large corporation that had several lines of Java server code and discovered that ” large maintainable apps in Javascript are harder to do than a language like Java” is a huge myth, writing several modular components that work seamlessly together is hard in any language, it is all about preference and what will make you more productive. Uber’s codebase is mostly Javascript/Node.js and they seem to be doing just fine at scale. It is better to have a language that has optional type checking than strict. +> +> Back to the blog though, I use React Native and can code in Objective-C and Java, why? React Native allows me to use a flexbox layout and has all the benefits of an open source platform/ecosystem +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — November 11, 2015 at 5:26 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22422)) + +> Shai Almog says: +> +> I would tend to agree that you can write horrible messy code in any language and great code in any language. Developer skills are important. +> +> One “illness” that Java developers have is over abstraction and over complicating everything, but it seems JavaScript developers have picked up some of that flu as well see: [http://geek-and-poke.com/ge…]() +> +> About Uber, its a startup hence no legacy code maintenance and highly controlled architecture. Keep in mind that no corporation will advertise the “pain” of working on their codebase. +> +> Back to the blog post, Codename One has been open source since its inception (which was far before react native was even conceived) and has had flexible design layouts that work for all devices from before that. +> +> If you prefer JavaScript as a language that’s totally fine, to each his own. The blog post is aimed at Java developers who sometimes get the sense of “the grass is greener” when JavaScript developers talk about how X is easier. That’s just not the case. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Jeff Carver** — January 16, 2016 at 8:06 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22533)) + +> Jeff Carver says: +> +> Hi Shai, +> +> I ran across information about Codename One while researching Google Flutter. CN1 looks interesting but Java is one of the few languages I never bothered with. Someone in an earlier post mentioned Delphi and I still think that was the greatest language/IDE ever created. +> +> Anyway, for someone who has focused mainly on Actionscript, Javascript, and PHP for the last several years, what suggestions could you provide for getting started in Java and CN1? I guess I’m trying to figure out how comfortable one has to be with Java before attempting to use CN1. +> +> I have already evaluated numerous other products in this space including React Native, Native Script, and various HTML/PhoneGap platforms. The best I’ve found so far is Tabris.js but it doesn’t appear to have any serious backing, is almost completely unknown, and thus may not be around for long. +> +> Thanks in advance for any information. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — January 17, 2016 at 4:39 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22677)) + +> Shai Almog says: +> +> Hi, +> We’re all big Java advocates around here and have been doing Java for so long we don’t even remember learning Java. So we’re possibly the worst possible reference for getting started if you don’t know Java to begin with. +> +> For complete newbies there is [http://codapps.io/]() but I think it will be too simple for you as its designed for people with no coding experience. +> +> Java is a relatively simple and strict language so this might be a bit of a culture shock when coming from loose languages like JavaScript. Also a lot of our code/demos predate the Java 8 support so a lot of those would look very verbose to a guy coming from that background. +> +> Since you already know several languages I think just picking up Java and looking at the code should be pretty intuitive without an explicit tutorial but I don’t really know… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **void777** — January 25, 2016 at 11:19 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22524)) + +> void777 says: +> +> Java works for iOS apps? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — January 26, 2016 at 3:13 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22659)) + +> Shai Almog says: +> +> Ahem [https://www.codenameone.com/]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **adamski** — January 30, 2016 at 9:30 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22441)) + +> adamski says: +> +> I’m not a massive Javascript fan but I do think React Native has hit a good spot. I am using it for cross-platform UI and the core of my app is written in C++ with the JUCE framework. This gives me the best of both both worlds, tight performant code where I need it and quick to build UI across mobile platforms. +> Had I heard of Codename One before I started I might have given it a look 🙂 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Gabriel Matusevich** — March 11, 2016 at 6:43 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22609)) + +> Gabriel Matusevich says: +> +> hmmmmm I think you are being a bit unfair, react native has … a few years of development and it’s already cruising, also you are not talking about Rapid App Develpoment, with React Native I’m able to write apps in MUCH less time not to mention that Android Development in Java is a ginormous pain, with React and Redux, mobile dev is a paradise in comparison. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — March 12, 2016 at 3:28 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22755)) + +> Shai Almog says: +> +> I’m comparing it to Codename One which has only a slight advantage in terms of years so this is totally fair. +> +> Android development does suck. One of the problems in React Native is the fact that you need to setup an Android environment to get started. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Simon** — March 12, 2016 at 5:02 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22619)) + +> Simon says: +> +> Wow I think you have to be a particular breed to think that the Java was simpler than the React code. For one it was about seven times as long and as soon as I see stuff like ‘public void’ and ‘private static final’ I have the urge to go running for the hills. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — March 12, 2016 at 5:12 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22629)) + +> Shai Almog says: +> +> It isn’t longer as shown in the sample above its roughly the same size. Notice that Java 8 syntax is pretty terse when used effectively. +> +> Yes there is some boilerplate but boilerplate isn’t program logic hence doesn’t add to complexity. +> +> Type safety is commonly accepted as a preferable way for a large number of developers (e.g. Typescript) so if you prefer Java (which great many do) then React Native doesn’t add any advantage. If you prefer JavaScript then this becomes a religious debate as there is no debating programming preference. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Simon** — March 12, 2016 at 5:18 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22483)) + +> Simon says: +> +> Actually its just over twice as long, (I did a character count in a text editor). Yes that’s what I mean by a ‘particular’ breed ie programmers. Anyone more casual will likely prefer javascript. But React Native is far from being just javascript. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — March 12, 2016 at 5:41 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22584)) + +> Shai Almog says: +> +> Did you include the embedded XML? Did you include their bootstrap files which aren’t listed in their code but do exist there? Our code is pretty complete (with the exception of the package/import statements) so it includes all the UI and lifecycle code. Their examples rely on some generated files that aren’t listed. +> +> Java IDEs make Java MUCH easier for novices and type safety removes a lot of newbie mistakes. For experienced developers the ability to refactor a Java application from a stranger is a huge advantage. So I would argue that Java is WAY easier than JavaScript but I’m obviously highly biased. Every coin has two sides and I gave the example above of JSON processing which JavaScript’s ducktyping really simplifies. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Simon** — March 12, 2016 at 5:49 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22765)) + +> Simon says: +> +> You can’t include things that are embedded or not listed ‘cos they don’t bother you or make things more complex. The more stuff that is embedded or behind the scenes, the easier it is to just get on and program and the code itself looks much more simple. +> +> I truly wish Java was simpler ‘cos I would love to learn it. Tried and failed. Actually my favourite is PHP which is even more straightforward that javascript. I actually prefer Javascript variants like JQuery and React Native. The less characters typed to achieve something, the simpler it appears. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — March 12, 2016 at 7:34 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22773)) + +> Shai Almog says: +> +> Does it not bother me? +> +> You need to control lifecycle in any non-trivial application so it being hidden in a separate file is pointless. I could break my sample into two files and achieve the exact same results as react native so that doesn’t really measure anything realistic. +> +> If you don’t like Java then you are clearly not in the demographic I aimed this article at. It’s aimed at people who like and appreciate Java and its advantaged but are looking at React Native thinking the other side of the fence might have greener pastures. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Alex** — March 28, 2016 at 2:36 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22446)) + +> Alex says: +> +> I just threw up in my mouth a little. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **adamski** — April 6, 2016 at 8:17 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22816)) + +> adamski says: +> +> React Native is only partly about Javascript. Its more about the architecture. And the amount of 3rd party modules available via npm. And the amazing developer community, that i’ve not seen anything like before. +> +> I’ve settled on RN for the UI of my app, and thought its not been without its hurdles I feel like its a good way to do cross platform mobile development. I’m actually more comfortable writing C++11 (the other half of the app is in C++) than Javascript but since ES6 and ES7 things are looking much better. Yes it still has its warts but so does every other language in one way or another. I started writing my app UI in Swift for iOS with the intention to write the Android UI in Java but RN looked like a much better proposal to save rewriting all the UI logic for each platform. I’d have given your product a spin if I’d known about it sooner. +> +> Your comment “With apps you need to go thru Apples approval process” is not true for javascript only updates – there are tools to enable pushing javascript only updates to installed apps thereby circumventing the Apple approval process. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — April 7, 2016 at 3:18 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22565)) + +> Shai Almog says: +> +> You can say that about any major framework. E.g. Java itself is not about Java as much as the JVM… The Java developer community has it’s own benefits so I wouldn’t go into an argument over those. +> +> Dynamically downloading JavaScript is something that used to be prohibited, this makes sense as it somewhat eliminates the value of the human review process. Notice that you still can’t push out real updates and need to go thru review if you make major changes although it’s unclear how Apple can enforce such distinctions once they opened that door. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Osei Fortune** — April 7, 2016 at 8:19 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22573)) + +> Osei Fortune says: +> +> I think typescript should help make large JavaScript projects easier to maintain +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Don't Bother** — April 20, 2016 at 11:22 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22693)) + +> Don't Bother says: +> +> >Javascript are harder to do than a language like Java” is a huge myth… +> +> It’s not a myth it’s a sad truth. The reality is that on large JavaScript project people just afraid to make any serious refactoring because you never know what will break and when. I have experienced this many times. If you have not seen this it means you have not seen any large and complex project. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Don't Bother** — April 20, 2016 at 11:24 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22527)) + +> Don't Bother says: +> +> True but TypeScript is a not JavaScript. It is different language. And it has huge difference which is defined by world “Type” :-), and it has other things which are not present in JavaScript. It is same as if you say that Swift will make javaScript apps easier… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Chromonav Kulkarni** — April 26, 2016 at 7:21 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22768)) + +> Chromonav Kulkarni says: +> +> bro decide are you novice or a pro. Javascript is for people who learnt everything and are in search of superpowers.Js because of fluidity and simplicity and ability to implement suitable programming design pattern needed to get things done. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Chromonav Kulkarni** — April 26, 2016 at 7:30 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22775)) + +> Chromonav Kulkarni says: +> +> Java is a beautiful language and carefully designed with gr8 toolset; but lets face it: Javascript happened to be in middle of web evolution. It has simply evolved to a whole new level. +> Oldies like you may not appreciate beauty and simplicity of current javascript ecosystem. +> But theres one thing you should keep in mind : Atwoods Law: +> Any application that can be written in JavaScript will eventually be written in JavaScript. 😜😜 +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Chromonav Kulkarni** — April 26, 2016 at 7:46 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22596)) + +> Chromonav Kulkarni says: +> +> lets compare community following, rate of growth, current apps in production. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — April 26, 2016 at 8:06 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-21509)) + +> Shai Almog says: +> +> So was Java, livescript was renamed to JavaScript to pick the traction of Java. Either way this isn’t so much a Java vs. JavaScript but rather a React Native vs. Java. So all/most of your points aren’t really relevant here. If you embed JavaScript in a native app you open up a lot of problems and lose a lot of benefits of JavaScript. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **oojr** — April 27, 2016 at 5:21 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-21557)) + +> oojr says: +> +> True but you can say that about any large Java projects as well +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Chromonav Kulkarni** — April 27, 2016 at 2:21 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22825)) + +> Chromonav Kulkarni says: +> +> React Native inherits all the features of javascript essentially it is javascript++ +> React way of combining all concerns and dividing of problem has one major advantage: +> Code Reuse. +> The massive scale of code reuse possible and with a vibrant Js community it is possible to production ready apps within fraction of time. +> React Native inherits powers of both worlds and combines it with awesome react way (i love i don’t know abt you.) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Chromonav Kulkarni** — April 27, 2016 at 2:24 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22694)) + +> Chromonav Kulkarni says: +> +> End justifies the means. React works well for Facebook helps them churn feature updates faster. It is helping me the same way. I don’t care if i am going backwards and forward +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — April 27, 2016 at 2:25 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22528)) + +> Shai Almog says: +> +> So it inherits DOM access? +> Can I take JavaScript code off the internet that relies on CSS and have it work? +> +> Nope… +> +> It’s either native or it’s web. React Native stands in the middle and it pays for that, compile time, build process, install native tools etc. It has some benefits from JavaScript (fast preview etc.) but don’t try to present it like a panacea. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Ben** — May 9, 2016 at 9:31 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22776)) + +> Ben says: +> +> Several moot arguments here: +> +> The proposed async/await syntax is supported by default. You needn’t trifle with promises and can wrap fetch calls in try/catch blocks. +> +> Synchronous live reloading is supported, however, hot reloading will swap out individual components in realtime. +> +> JSX is completely optional, and compiles to plain JavaScript React.createElement() calls. These calls can easily be sugared using React.createFactory(). +> +> Facebook’s own [Nuclide.io]() is conspicuously missing from the Environment debate, as is the wealth of open source modules available from NPM. Facebook Flow is likewise excellent for terse static type support replete with compile time errors, and Jest was built specifically to unit test React components. +> +> After installing the Android SDK and necessary APIs, it takes only several brief commands to bootstrap then run a React Native app using the provided CLI. The same can be said for physical devices. +> +> I’m aware some of these features may not have been implemented or mature last November, but would like to ensure nobody is given a wrong or unilateral impression should they wish to try React Native. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — May 10, 2016 at 4:08 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22883)) + +> Shai Almog says: +> +> I don’t think react native lacks in the department of advocacy or visibility so if people get the wrong impression about it this usually biases in the other way. +> +> Notice that you need to install the Android SDK and then the iOS SDK and then the Windows SDK and then rewrite for web… You also need to adapt code as it isn’t a WORA solution… We actually allow you to install one plugin and it “just works” on everything. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **khle** — June 25, 2016 at 12:14 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22633)) + +> khle says: +> +> Interesting take. You probably knew this would be an unpopular opinion. Anyway, I didn’t read through all the comments so maybe someone else already said this. But one advantage with React Native is the same skill set can be used to write web applications. And with JS, one can write NodeJS on the back end. So maybe the same devs can do mobile, web and back end. For some companies, this could be advantageous. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — June 26, 2016 at 4:50 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22877)) + +> Shai Almog says: +> +> If you bring server programming into it then Java has a huge upper hand with more than a decade of scale in the enterprise and far more diversity there… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Nicolás Schürmann Lindemann** — July 5, 2016 at 12:25 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22772)) + +> Nicolás Schürmann Lindemann says: +> +> Java 8 seems to have a lot of good features now!, i remember back in the old days making an ajax call in java was a pain!, even trying to simplify it with libraries was difficult. I agree that strong typing adds a lot of ease in development and mitigates bugs. I think that the only complain about this is that you are comparing 2 synchronous codes while the JS call is being asynchronous. And also is the implementation of promises and the fetch API in ecmascript 6. Also the promises API implements a “catch” method that is used for errors management (therefore, no try/catch) it accept functions as callbacks so you can compose more easily. The code that you written was very imperative. Also the advantage/disadvantage of javascript is in fact the loose typing. Some loves it, others hate it. It gives you a lot of freedom in expresion, but you can get bugs that you will only get in production unless you do a lot of testing or add strong typing (typescript, flow). +> +> I believe that something like this may be more comparable and will let understand the benefits of promises and js: +> +> fetchData: function() { +> fetch(REQUEST_URL) +> .then(toJson) +> .then((responseData) => dispatch(updateRows(responseData))) +> .done(); +> } +> +> and with a helper: +> +> const disp = fn => data => dispatch(fn(data)) +> +> fetchData: function() { +> fetch(REQUEST_URL) +> .then(toJson) +> .then(disp(updateRows)) +> .done() +> } +> +> I think it’s cleaner, less imperative though. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **WhoIsMeekMill?&kidcudi** — August 2, 2016 at 6:16 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22887)) + +> WhoIsMeekMill?&kidcudi says: +> +> Just another java/android developer feeling threatened that his market is disappearing. Nothing to see here folks. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **bertbeck** — August 13, 2016 at 3:54 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22984)) + +> bertbeck says: +> +> How much overhead (in app size) does Codename One add to a typical app (over native size) ? Any idea what is typical for React Native? I’m an IOS and Android developer – have worked with Xamarin – know all too well the pain of added and complex runtimes (and bugs created by the runtime by new releases). I’m looking for the best environment to co-develop IOS/Android and if possible Web and Native PC/OSX/Linux +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — August 14, 2016 at 4:19 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22921)) + +> Shai Almog says: +> +> Codename One Android apps are roughly 1mb and iOS apps between 3-5mb for hello world. +> So the overhead is relatively low. There are fluctuations in the implementations which is why we have versioned build which allows pro users to build against a stable release. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **yedidyak** — August 21, 2016 at 8:47 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22802)) + +> yedidyak says: +> +> You can simplify the JS asynchronous code by using async await, which is supported in React Native. The examle above would become: +> +> async function fetchData() { +> const responseData = await fetch(REQUEST_URL).json(); +> this.setState({ +> dataSource: this.state.dataSource.cloneWithRows(responseData.movies), +> loaded: true, +> }); +> } +> +> Far simpler. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — August 22, 2016 at 3:25 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22879)) + +> Shai Almog says: +> +> That does change the syntax and we use it quite a bit in our JavaScript port. But it doesn’t really change the language semantics. Native API’s rely on threads and the ability to control them, this is true both for Android and iOS. JavaScript relies on hiding the complexity of threads. +> There is a conceptual disconnect. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shailesh** — September 17, 2016 at 1:25 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22819)) + +> Shailesh says: +> +> Such a misleading title. Comparing Java and javascript is totally different than comparing react-native with codename. The reason react-native is way superior is because of react component model. Building complex UIs is such a breeze in react. It is a lot lot simpler to keep the UI in a consistent clean state in react compared to other frameworks where finding the view and updating it, keep it in sync is such a pain. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — September 17, 2016 at 4:11 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-24222)) + +> Shai Almog says: +> +> Codename One is Java based and shows what can be done with Java for mobile. It’s not as known as Java so I chose to use Java in the title since a lot of the arguments (specifically terseness) relate to improvements in the Java language. +> +> Cleanliness is up to the programmer more than anything. +> +> What you are talking about is separation of concerns which sounds great. Until you try to use it in real life and need access to this thing from that place which you didn’t expect and you end up crossing the language barrier of the separation with constant zigzags. This makes grepping your code for issues and sources a huge pain. +> +> Concerns can be separated by convention as well all good programmers do that anyway and they don’t need a separate UI representation to perform that in Java. The big advantage in doing everything in Java is that I can place a breakpoint anywhere and inspect Java based UI state right in the debugger, I can mutate/animate the UI with the same code/syntax I use to construct it which makes refactoring much easier. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **IsMyBlueYourBlue** — October 11, 2016 at 5:58 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22929)) + +> IsMyBlueYourBlue says: +> +> Hmmm weird I don’t know why you say Java is simpler. For me the Javascript version is A LOT easier to read. I only have 7 years professional programming, is that a problem…? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Hristo Vrigazov** — October 23, 2016 at 2:28 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22981)) + +> Hristo Vrigazov says: +> +> I think my opinion would be pretty interesting… I started with Ionic and created a few apps, (have not written in React), and I like a lot of concepts in both JS and Java. To me, Codename One gives you more control, although more verbose. It is extremely easy to reuse code in Codename One due to the fact that you have the full OOP power with all its patterns etc. What is also cool is that you just use the IDE you know (IntelliJ in my case), and you can just send iOS, Android and Windows builds in the cloud and this way not to worry about configurations. Codename One also has amazing support. Javascript frameworks on the other side are very convinient with things like parsing JSON, callbacks, promises, which to me simplify the web, but these things can be used in Codename One also, if one wants, although slightly verbose. JS frameworks also have a lot of third-party frameworks that simplify things a lot (Codename One also has CN1 libs, but there are not as much out there). In my opinion, one should go the way that he likes best. For example, in my current app, I am actually integrating Codename One with Node.js backend, since the Loopback framework makes it so easy to quicky create REST APIs. No need to choose guys, learn the best of both worlds, don’t be close-minded. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — November 1, 2016 at 1:11 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22924)) + +> Shai Almog says: +> +> I used the react tools and Microsofts C# tools and xcode and Codename One… Obviously I’m biased but I am informed. +> +> Using Visual Studio is like traveling back thru time for a person using a modern Java IDE, it’s like using Eclipse after you used NetBeans or IntelliJ. It constantly fails on basic things, doesn’t provide valuable hints and its debugger is just plain painful (inspecting variables etc.). So while I see the theoretical logic of comparing it to Java I can tell you that in practice Java is far more refined. +> +> Atom is surprisingly good as an editor, in fact I use it a lot for asciidoc editing. But it’s no IDE. Most JavaScript tooling isn’t nearly in the same level. When I talk to JavaScript devs they argue about the “need” for tooling. As a guy who started Java during the beta of 1.0 I can totally sympathize, I used a text editor and command line rather than use C++ and preferred it over visual studio of the day (was it visual studio 92 back then?). Anyway, I was right at the time but when tooling came to Java they brought productivity to a completely different level and they might eventually do the same for JavaScript. JavaScript needs tooling more than Java because the code hides far more meaning than the Java code. +> +> That’s what you missed about the code problems in JavaScript. The problem is that the Java code is very clear in its intention you point at X in the IDE and the IDE will tell you it’s an integer. In JavaScript you don’t even know what “this” is. +> +> React native itself has a slew of other issues, it has one nice thing with is the live preview/update. That is something we have in the simulator with “apply code changes” but it’s still pretty cool to have it “on-device”. +> +> I’m not sure if our tooling will be simpler for you since obviously there is a “filter” when picking up any technology and getting your brain used to it’s “oddities” and if you are not a Java guy to begin with the habits might be too deep. But our tools are WAY simpler and that’s obvious even during the installation phase not to mention in final projects where the IDE can literally show you the where & what of everything. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Justin L Mills** — November 9, 2016 at 4:42 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23181)) + +> Justin L Mills says: +> +> Can I code Haxe Java for Codename, Haxe can allow you to access most jars via -java-lib. Obviously you feel there are some advantages of your system over React Native but I could also use Haxe JS with React-Native, so what’s left beyond IDE’s when you consider some of the cross target Haxe libraries like Kha, OpenFL, Flambe, SnowKit etc… do you still feel that Codename One – a paid product offers something extra that Haxe developers might want to tap into for mobile development? It’s not a retorical question I am curious as I am aware that Haxe ecosytem does lack component support in many areas but at sametime is maybe nicer than Java or Javascript as a language 🙂 . Perhaps you could take a proper look and write another post around use of haxe with Codename One against maybe other options like Haxe c++ and Haxe JS wrapped. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — November 10, 2016 at 5:03 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22865)) + +> Shai Almog says: +> +> In the past there was a guy in the forum who ported Haxe to Codename One but hasn’t followed up. Codename One is an open source product with a commercial SaaS on top. I would argue that’s better than a completely free product as it guarantees professional continuity and support. +> +> I’m not familiar enough with Haxe and I’m not really sure why one would pick it. But lets do it the other way… You try Codename One and write a guest post from a Haxe developers perspective? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Justin L Mills** — November 10, 2016 at 11:33 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22846)) + +> Justin L Mills says: +> +> It seems I need to install lots of tools and it’s not really clear how I might use Codename One using just Textmate and Terminal, since fancy tools are great but would get in the way of a proof of concept of mixing Haxe with Codename One. +> An old tutorial of mine on using Slick and lwjgl jars with Haxe. +> +> [http://old.haxe.org/doc/jav…]() +> So is there a Jar file for the Codename One components, that I could hook up to the Haxe and then a way to wrap the haxe jar up and send to your conversion servers? +> +> In terms of React there are native externs support for Haxe and some addons, Haxe probably has better strict typing than Java, being a bit more functional inspired so the js typing issues disappear. +> [https://github.com/tokomlab…]() +> [https://github.com/kevinres…]() +> +> At moment where I work I am not excited by the android solutions looking inside put me off learning Android java, so expect Codename One approach might do better, my collegue is creating React/Reflux touchscreen app, and feels it’s simpler than the AIR approach we have used for Kiosks in the past. So I would really be interested to know if Codename One could be easily hooked up to Haxe Java and I could prototype a similar Kiosk app with it, but I have no interest in coding in Java or really Javascript 🙂 And the docs online do not really give me the information I would need to set up a project that used Haxe Java for application code. +> +> Having learnt code through flash, I am not convinced by the closed source support arguments you use, since I saw Adobe largely desert as3 developers. But I know at work they love the C# backend supported approach, so there are swings and roundabouts, often closed provides better tooling, but you can’t branch the project if you don’t like where it’s going. +> +> But don’t expect you have time to setup a codename one haxe java demo but I would be very curious if you did. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — November 11, 2016 at 7:22 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23185)) + +> Shai Almog says: +> +> There is actually very little to install for Codename One but using it without the tooling goes a bit against the grain of what we are trying to accomplish. Codename One has far fewer dependencies than any other tool out there and is really just an ant project with no external dependencies other than a couple of jars. +> +> I’m not sure I can help you with Haxe as it’s not a point of interest/focus for us. If you don’t like Java then Codename One might not be the best solution for you at this time. +> +> The Adobe argument doesn’t fit since Adobe didn’t open source flash. Codename One is open source (including the VM, ports etc.)… It’s more like Android in that sense. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Jason Nathan** — December 18, 2016 at 12:41 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22968)) + +> Jason Nathan says: +> +> My sentiments exactly. I think a deep dive into JS is needed to make a proper comparison. The Promise and “then”-problems described are really the woes of someone newly discovering JS, for example. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — December 18, 2016 at 4:45 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-22837)) + +> Shai Almog says: +> +> We use futures in our JavaScript port. Nope. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **ie5x** — January 11, 2017 at 10:29 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23241)) + +> ie5x says: +> +> I am not sure why you are comparing a language with a tool? Shouldn’t you either be comparing codenameone with React Native, +> or Java with JavaScript? +> +> Anyways, using async/await syntax which is completely supported in React-Native – +> +> fetchData: async function() { +> try { +> let response = await fetch(REQUEST_URL), +> responseData = response.json(); +> this.setState({ +> dataSource: this.state.dataSource.cloneWithRows(responseData.movies), +> loaded: true, +> }); +> } +> catch (err){ +> this.setState({ +> error:err, +> loaded:false +> }); +> } +> }, +> +> Done! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — January 12, 2017 at 5:08 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23162)) + +> Shai Almog says: +> +> I did compare with Codename One. Java has better name recognition so I used it for syndication purposes. +> The async/await approach was mentioned in other comments. It’s not exactly a thread alternative more like futures which is fine but not the same. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Nitin Bansal** — February 4, 2017 at 7:39 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-21647)) + +> Nitin Bansal says: +> +> If JavaScript was/is so great, then why has it started to seem more and more like Java after ES6? And so goes for Java too, where it has started to seem more like Python after Java8. The fact is none of the languages were perfect. But, as time lapsed, and so the programmers’ experience in using these languages, and also the fact that current projects require exposure to more than one language, people have started adding more and more best features from other languages. Hence, java introduced lambdas and functional interfaces, while javascript introduced classes, which it hated at one time so much. Newer languages such as Go and Rust and Swift already come with balanced set of these features. As time goes by, we’ll see more of unite among the way languages handle their syntax, getting more and more diversed on where they fit best. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — February 5, 2017 at 8:17 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23249)) + +> Shai Almog says: +> +> I agree there is a lot of convergence, it’s an artifact of taking a language designed for one purpose and re-purposing it after the fact. +> +> The languages are still very different especially when it comes to types, encapsulation etc. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Stan** — February 8, 2017 at 5:41 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23089)) + +> Stan says: +> +> and I’m willing to bet that Facebook has got a whole bunch of lower level code to suplement the javascript. I’ve been a software engineer for over 2 decades and have coded in many languages (C/C++, Ada, Fortran, Pascal, assembler, etc) and I’ve been coding Java since 1998 and by far, it’s still me language of choice hence which is why I’m starting to use Codename One. Not knocking Javscriipt because I like that as bwell and have been using it since t6he early 2000s but not much comparison to java as a heavyweight language. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Stan** — February 8, 2017 at 5:44 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23244)) + +> Stan says: +> +> Totally agree and has anybody heard of this new phenomena called “Javascript Fatigue”? It’s dizzying the number of frameworks, libraries, packagers and add ons that one must know… +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **anonymyst** — February 17, 2017 at 11:51 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23310)) + +> anonymyst says: +> +> Ya well Java doesn’t hold a candle to Swift. Besides, your claim may be true in some ways, but in the way that’s most glaring and important to most, is speed… I’ve got junior dev react native programmers that can code outcomes much faster than your senior dev java developers. Another way in which it fails, is in it’s inability to deliver a consistent user experience across 2 platforms… react native gives my clients a single codebase, which makes better business sense, so in that sense, it’s a major fail for both Java and Swift. So I’d hold back in speaking in such extremes as “superior in every way,” because it makes you sound biased and ignorant. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — February 18, 2017 at 5:59 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23378)) + +> Shai Almog says: +> +> To each his own. I don’t like Swift personally and even if you are a big fan of the language it needs years to reach the maturity level of Java in tooling, 3rd party support, resources etc. +> +> I agree that a lot of Java programmers tend to “overthink” problems especially when it comes to the monstrosity that is Java EE. There is a cultural problem there. In JavaScript react you have the exact opposite of patchwork and unawareness of production/security problems that might occur. I’m sure that you are comparing react programmers to native Android programming which is horribly broken. +> +> I am biased (notice the site you are on) but I’m quite well informed. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **carlos** — March 21, 2017 at 7:41 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23260)) + +> carlos says: +> +> Hi Shai, +> +> A quick peak at your CodenameOne looks great. In the past I’ve done a lot of Java client side development but I think you should know that React Native is way better than using Java because it provides an evolved way of developing GUI client software. I mean your method looks and feels like the 90’s when Swing was the state of the art on GUI development. Techniques have evolved to include a combination of imperative and declarative techniques as well as auto binding data. There are several Javascript frameworks that use these techniques (Angular, Aurelia, Ember, etc) but React is by far the simpler and most powerful of the bunch and hence why it is so popular. +> +> Use React Native to develop a full blown app and experience what is great about it and hopefully you can incorporate that into your CodenameOne system. +> +> Best of luck. +> +> Carlos. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **carlos** — March 21, 2017 at 7:48 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23100)) + +> carlos says: +> +> Yes, and Webstorm is a fantastic Javascript IDE +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — March 22, 2017 at 4:57 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23338)) + +> Shai Almog says: +> +> Hi, +> you are comparing Swing an old and outdated implementation of the idea with new implementations of JS frameworks so naturally the former will feel old and the latter will feel new. +> +> The imperative nature of these frameworks isn’t there in the name of progress, it’s in place to workaround the oddities and pains of the DOM/JavaScript combo. Imperative frameworks are problematic as they are harder to learn and debug due to the underlying “magic”. +> +> Where do these imperative frameworks provide any real world concrete advantage? +> +> They aren’t more terse (as I demonstrated more than once). +> +> They aren’t easier to debug or understand since their flow isn’t linear. So where is the progress? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **carlos** — March 22, 2017 at 6:29 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-21569)) + +> carlos says: +> +> Shai, +> +> Your system, CodenameOne, is new so it should feel new but instead it looks like old technology using old techniques. You could had done something like JavaFX or better yet React Native but you are doing things like Swing !!! Your choice. +> +> You got imperative and declarative mixed up. Markup is declarative, Java is imperative, React combines amazingly imperative and declarative techniques. +> +> > The imperative nature of these frameworks isn’t there in the name of progress, it’s in place to workaround the oddities and pains of the DOM/JavaScript combo. +> +> Wrong. Their declarative nature has nothing to do with pains of DOM/Javascript. React Native has no DOM. Adobe Flex uses declarative techniques without DOM, so does JavaFX, etc. +> +> > Imperative frameworks are problematic as they are harder to learn and debug due to the underlying “magic”. +> +> Wrong. Some of these frameworks are harder to learn and debug but React is super simple and easy to debug, reason, read, etc. Do you think that it would take off like this if it was hard? +> +> > Where do these imperative frameworks provide any real world concrete advantage? +> +> Code is simpler (and faster) to read, write, maintain, debug, better architecture, re-use, scale, etc +> +> > They aren’t more terse (as I demonstrated more than once). +> +> Your ‘demonstration’ is a joke. Do a full app, with UI building code and event handling, etc. Do something like this: [https://github.com/junedomi…]() +> +> > They aren’t easier to debug or understand since their flow isn’t linear. So where is the progress? +> +> Wrong. You really need to actually learn something new and appreciate why it is better than what was before. You sound like a proud horse carriage owner praising its advantages over the car. Pride is preventing you from reaching your full potential. +> +> Carlos. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — March 23, 2017 at 6:23 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23121)) + +> Shai Almog says: +> +> Codename One is based on work we did at Sun Microsystems during the time JavaFXScript was developed. So it predated JavaFX and React by several years. JavaFX’s failure and counter-innovation is something I just don’t want to go into as it’s a long and deep argument. +> +> There are quite a few things I’d like to correct here but I’m pretty busy with the bootcamp to write something extensive. Our system mixes some concepts from UI and model like Swing used to. Some developers might think that’s old… The fact that iOS/Android take that approach natively (because they are old?) is probably important. +> +> React is simpler than doing barebones AJAX but it’s not simpler than just coding the UI directly. Not every idea that comes later and fits into a new structure is better e.g. Linus came back with monolithic kernels years after the debate for microkernels “won”. The reason for Reacts success relates to the problems of the system it is layered on top. +> +> We took an age old solution to a common problem and provide a lot of advantages/capabilities you just can’t do with React Native (and yes I based this code on the react tutorial demo so I’m very aware of what’s there). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Rick** — April 8, 2017 at 10:08 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23427)) + +> Rick says: +> +> But aren’t you missing the whole point? I hardly believe anyone will claim that non native code is better than the real deal. +> +> But React is a response to a time when we have a highly fragmented UI market (thanks Apple Store, Google Play, etc). +> The idea is to leverage device homogeneity and at the same time minimize the performance impact as much as possible. Here React is just very good. You can quickly code an average mobile app in a short time that will run with minimal changes, if at all, on various devices. Try keeping a solid dev team with frequent releases using native only. +> +> And either you like it or not, functional style programming is very important now, more than ever actually. Functional style programming leverages the computing power of multi-core systems and aides with concurrency issues to render them almost trivial. Even the event driven paradigm helps with linear code design by dropping the need for stateful concurrency marshaling entirely. The code you say is hard to read is not when you learn how to go about these paradigms. +> +> And how about the top-down data flow model in react? This means no event/data cross binding hell. +> +> I have 19 years experience in this field, so I’m almost as old as you in this regard. And I repeat, I acknowledge you do have very good points, but your blog doesn’t make sense to me. It’s like comparing cars to planes A Ferrari is definitely an immensely better machine at its job than a Cessna, and although both address the same common need, transportation, they both respond to different circumstances and socio-historical driving forces. The Cessna is able to solve the much more sophisticated need for fast travel vs convenience vs cost debacle, and that is the point. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — April 9, 2017 at 4:02 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23261)) + +> Shai Almog says: +> +> Codename One is more native than React Native. On iOS code is translated to native code and compiled using XCode not run thru JavaScript JIT. On Android Java is running directly on the Android VM. We allow embedding native widgets (e.g. Google Maps etc.) so in most aspects Codename One is more native. +> +> However, let me attack the “native is best” dogma that has undertaken our industry. That dogma didn’t exist 10 years ago. It came to be because iOS UI’s were so radically different there was no other way, the same was true for Android. Over the years both Android and iOS converged a lot. The cross platform tools have also made great strides and are now rivaling native. +> The fact that you can take a design, caching system and features quickly everywhere is huge in terms of delivering fast functionality and update to your user base. Update speed for applications is probably more important than anything in mobile. +> +> I’m not a fan of functional programming for real applications. It’s great for math but without encapsulation or imperative style it becomes a maintenance problem down the road. The idea that multi-core will be leveraged by this style is one that the JS crowd has been pushing for years, it “might” be valid for NodeJS but it’s not for react native where the UI is single threaded and any bit of “adventure” off the main UI thread will demolish you. Our GC & networking run in their own threads and make use of multi-core and since our EDT is separate from the main OS thread we leverage multi-core better while increasing portability. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **lambdatoast** — May 18, 2017 at 10:42 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23365)) + +> lambdatoast says: +> +> You don’t have to have your codebase in JavaScript when using React Native (e.g. I’m using React Native and the code I write is in a language whose static type system is light years ahead of what Java will ever reach). +> +> So this blog just post amounts to you showing that that bit of Java code that’s more familiar to you (and which has type checking, although caveman era-type checking that doesn’t track side-effects in the types, and is therefore doomed to become a pain to reason about as it grows…. sorry, that’s the Haskeller in me, ranting), reads better to you than that dynamic language garbage they used in the React Native example. +> +> BTW not only are we able to use something other than JavaScript with React Native, but we can even use plain old JavaScript, and for the parts we choose, add type annotations in the comments, and have FB’s Flow type check it *statically*, aaaand Flow’s type system is already more advanced than Java (as in stronger type guarantees. e.g. isn’t it pathetic how Java can’t type-track uses of NULL at compile time. Ugh). +> +> BTW, to all peoples interested in static typing: Please check out something like PureScript + React (or React Native, or both), in order to understand why languages like Java remain in the dark ages of static typing. Do NOT get your idea of what types can do for you based on OOP languages like Java, which ruin all typing guarantees with their out-of-control side-effects. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — August 14, 2017 at 7:07 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23603)) + +> Shai Almog says: +> +> No. It’s the exact same number of lines and works perfectly on iOS. Clearly you haven’t read what I said. +> The logic can be shared just as well in Java or even better… Great you can share 80% of the styles in CSS (I call bullshit but fine) in Codename One you can share 100% of the styles. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Albert Gao** — October 9, 2017 at 4:15 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23666)) + +> Albert Gao says: +> +> React native could share codes across web and native, even for the UI (Production ready for a long time and already some big names did that in production like MS and Airbnb). And it has an unique pattern to encapsulate the related UI and logic into a component. These are something CodeNameOne just can’t compete with. +> +> But I do see the use cases for CodeNameOne, as our company, we have a web site which is not based on react stack, and we adopted kotlin in part of our back-end. It makes CodeNameOne perfect sense for us when considering a solution for delivering mobile app. And as I can see from the doc, CN1’s app life cycle is pretty straightforward and easy to understand for a mobile developer. +> +> I just wish you guys could: +> 1\. Make the import of kotlin lib (coroutine and reflection) viable, so we could use CN1 to write an app while still use our existing kotlin libs. +> 2\. Wish the new UI designer could work with kotlin soon, come from a python cross-platform framework named Kivy, any time you start to code the UI via code (not only python, for java, kotlin, javascript…). It makes you such a pain when the UI becomes complex. I can see the UI designer will generate a XML which is a good sign. +> 3\. Add some 2-way binding or at least 1-way binding mechanism to lessen the code to write. +> +> There are always good thing to take from new tech or ideas. Use that to strengthen CodeNameOne would be better. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — October 9, 2017 at 7:59 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23787)) + +> Shai Almog says: +> +> I think a better place for this is in the kotlin post as it relates more closely to that. We can compile codename one apps directly to JavaScript with no code changes so I’d say we are way ahead if what you are trying to do is build an app and not a website. +> I think partial code sharing is problematic, you end up having to constantly test any change to shared code lowering the value of the reward. A lot of the abstractions and patterns of react are there since there to abstract issues in the underlying platform. Abstraction is less valuable when you have one common abstraction for everything, when that exists you can just work directly and get more platforms as a result. +> +> 1\. I’m not sure about the complexities of those. I think some of that should be portable. +> 2\. That’s doable. The main obstacle for doing this is people/resources. +> 3\. We have a properties binding framework, it’s oriented at Java but might work well for kotlin see: [https://www.codenameone.com…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Albert Gao** — October 9, 2017 at 8:08 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23793)) + +> Albert Gao says: +> +> Thanks for the reply. If I understand you right, it’s more like a web-first or app-first approach difference now 🙂 And CN1 is the latter, makes sense now 🙂 Will surely look into that properties binding framework, as far as I can see, my simple example works really well with Kotlin. +> +> And thanks for the reply. You are very responsive for my questions which split over places 😀 (And you are even more responsive than some big name open source project) Your attitude to the product will SURELY help my evaluation! Appreciate! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **nathan32** — October 13, 2017 at 7:54 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23574)) + +> nathan32 says: +> +> I think the biggest disadvantage of codename one is the “Environment”. React Native is truly opensource. As for mac version we can buy a mac mini and set it up like a server for the whole office and it costs me just $499, that equals just 6 months of professional subscription we pay for codename one. If we’re uncomfortable or prohibited by client contract from uploading the content to a 3rd party server we shell out $399 each month, honestly we can equip my whole office with macs in what we would pay CN1. +> As for horrible Android emulator, React Native provides an easy way to build app using Expo and even preview it on ios/android mobile using the Expo client ([https://expo.io/)]()), So just scan the code and it shows a preview on the device. Any code changes is reflected instantly on the device. That one feature has made our lives a lot easier. Easy DOM manipulation is good for business apps interacting frequently with a backend. +> Except for that I find both toolkits similar, the standard gui principles are used. It boils down to the language of your preference (both JS and Java fall on the disliked side of things for me). +> We went with React Native for just those reasons, If you could provide a truly opensource toolkit we’d have been on the side of Codename One. A simple VBox image of a pre-configured server would make CN1 more popular, to test this just release one vbox image and see for yourself. Just the response to a linux based server for android builds might surprise you. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — October 13, 2017 at 8:20 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23801)) + +> Shai Almog says: +> +> Your response reads like one of someone who has made up his mind and is trying to justify it. Just in case it isn’t here’s the way I see it: +> +> – We are 100% open source just like react native. No less. React native doesn’t have build servers and sharing a Mac doesn’t really give you anything remotely close to that experience. Saying that this piece which doesn’t exist in the open source project is the reason we aren’t as open is like me saying that React Native’s VM isn’t open source like our VM’s are. +> +> – You can get a basic subscription for your office for less than a cost of a Mac if all you care about is the build server functionality. Having said that the pro subscription includes FAR more features than that and full support. That’s something you can’t buy fro any amount of money in react. You can’t pay Facebook (not a 3rd party) to give you professional support. +> With the enterprise subscription you buy a lot of things that go well beyond offline build, specifically you buy partial control over the direction of the project and a direct line to us. There are many other features besides offline build etc. Its meant for enterprises not startups so if price is an issue don’t buy it. The fact that there are paid options is an advantage for us, not a disadvantage. +> +> – We support Kotlin not just Java although Java is the main target. We could support any language supported by the JVM from Ruby to Jython to Scala etc. There is even a nifty guide Steve wrote explaining the steps he took in porting Kotlin (FYI he also added unofficial support for Mirah a few years back): [https://www.codenameone.com…]() +> +> – There used to be a 3rd party offline build project, we hired its maintainer (not to stop the project, he’s just a really great hacker). When that project ran very few people used it, it might still work but most people don’t really care about that stuff so the last paragraph should be reversed. “You would be surprised”. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **nathan32** — October 13, 2017 at 8:52 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23762)) + +> nathan32 says: +> +> No its not, until you are using custom native modules refer [https://facebook.github.io/…]() You can simply use expo client ([https://expo.io/)]()). The opposite however is a point of concern. I can do a native build in case of React Native while Codename One native builds though not impossible are costly as hell $400/mo. I can dedicate a machine for doing builds for that amount. So effectively for one month of Codename One Build server I can get a react one for lifetime. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — October 13, 2017 at 10:00 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23755)) + +> Shai Almog says: +> +> Native builds in Codename One are between free (with quota limits) to 19USD per month with no limits. I have no idea why you decided the $399 enterprise version is needed when about 1% of our users actually pick that option. From that 1% very few use the offline builds which even our promotional material recommends against see: [https://www.codenameone.com…]() +> +> Again you totally ignore the fact that you can use our source code for free and that it delivers pretty much everything. You also ignored all the other points I made. +> +> About expo, that is indeed a nice feature. We have a proof of concept that will allow something similar in Codename One (on-device-debugging) without the build cycle. Unfortunately this would require some work to bring to production. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — November 7, 2017 at 11:01 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23729)) + +> Shai Almog says: +> +> John. We make our money through the SaaS product which is our chief source of income. That guarantees sustainability unlike a company like Facebook or Google both of whom proved they have no problem throwing away a product used by millions because it didn’t gather revenue… We only support push notification in the pro level but if you look in the parse plugin for Codename One you will find that this isn’t a requirement there. It’s not something we advertise as we can’t guarantee it but it works fine. +> There are also people and projects by third parties who use our source code to build their apps, if you look in our discussion group just the other day a user posted about a free plugin for building apps. Naturally that isn’t a sustainable model and you can’t expect us to support it. +> +> Legally we can’t publish “vbox images” as we can’t re-distribute Mac OS or Windows. Your assumption that our backend application is something a human being can reasonably setup with a guide off the internet is incorrect. Our architecture is ridiculously complex. +> +> About open source being free of charge. That’s just wrong. Free software != free beer. +> The fact that we charge is a huge advantage. If something breaks or needs fixing in a “free” product you are stuck. There is no one there. You can pay a consultant but that’s a coin toss. Here you have a guarantee by the authors of the product that we provide support. With Facebook even if you are a huge company you can’t buy that guarantee because react isn’t a product that makes money for Facebook. +> Furthermore, if you appreciate your craft you pay for good tools. There are 3 great Java IDE’s and the most popular among them isn’t completely free (IntelliJ). It’s still open source and it’s still a great IDE that is worth the money. We pay a large salary to our developers it makes sense to spend a little on their tools so they work more effectively. +> +> About expo it didn’t exist when I wrote the article. Regardless it’s nothing like Codename One which is a WORA solution something that React Native is not (based on Facebooks explicit definition). Build servers are possible with a WORA lightweight architecture but with a heavyweight architecture (one that relies on native peers for everything) this is problematic as you need a far larger set of testing devices to verify anything. Cloud build becomes a hindrance rather than an advantage in that case. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Nick** — February 26, 2018 at 4:48 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23951)) + +> Nick says: +> +> A little late but I found it amusing you speak very highly of “separation of responsibilities” but you have view rendering logic coupled tightly with your data fetching logic, which a framework like React encourages to actually separate (don’t know about Codename one). +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — March 3, 2018 at 12:12 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23765)) + +> Shai Almog says: +> +> Sure, it’s demo code so that’s how I treated this. I don’t think a framework should “force” separation. +> It sounds good on paper but when you need to cross the separation bounds to do some back and forth logic things start getting “hazy” and you end up having a lot of clutter all over the place just to pass through that artificial bridge. +> +> React native didn’t do that because it’s good engineering. That separation exists because the platform is in a different language and difference system. We let you access everything if you need to. Yes, power allows you to shoot yourself in the foot (i.e. threads) but it’s still more powerful to have the choice and languages that support encapsulation. +> +> FYI this article is really old and actually pulls a lot of punches from React Native. I should seriously revisit it since things are pretty different by now. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **James Line** — June 14, 2018 at 1:38 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23856)) + +> James Line says: +> +> To be fair the Android emulator has gotten a fair bit faster since you wrote the article. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Iftee Khar Ul Islam** — June 20, 2019 at 2:27 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-24117)) + +> Iftee Khar Ul Islam says: +> +> I like everything about CodenameOne, but I think there should be a **comparison with Flutter**, Google’s new framework cross-platform lover dudes may know it very well, I loved it but only thing that brought me here is that **CodenameOne doesn’t increase App size as flutter**, there’s other pros and cons but you should go with the one you like, I like both hence I will use both (there are migration tutorials for flutter, i.e. Flutter for Android devs, iOS devs, which enabled me to learn and use both) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Iftee Khar Ul Islam** — June 20, 2019 at 2:31 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23967)) + +> Iftee Khar Ul Islam says: +> +> A basic ‘Hello World’ app in flutter produces a 7.5mb file, where CodenameOne uses 1.7mb only, so for Small or relatively small apps using CodenameOne is a choice you won’t regret (Flutter may increase app size due to everything in Flutter is a Widget! and it also includes a C++ , Skia engine for performance which makes it’s size relatavely larger) … +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Michael** — September 16, 2019 at 11:18 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-23912)) + +> Michael says: +> +> There are an awful lot of [comma splices]() in this article. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Merkle Groot** — February 7, 2020 at 11:51 pm ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-21377)) + +> [Merkle Groot](https://lh3.googleusercontent.com/-wgRg-3_Yiws/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3rfK-pe_xm40uIAPWNZP0XwW8eHSwg/photo.jpg) says: +> +> React Native lets me use one code base for Android, IoS, Web, UWP, and cross-platform Desktop. +> WHERE IS YOUR JAVA NOW????? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Shai Almog** — February 8, 2020 at 4:43 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-21380)) + +> Shai Almog says: +> +> Ahem. Did you look at the website you’re in??? +> We target all these platforms and unlike react native we’re even more portable in terms of the code base, it’s truly one code. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + + +### **Crab Synth** — May 22, 2020 at 1:56 am ([permalink](https://www.codenameone.com/blog/java-is-superior-to-react-native-in-practically-every-way.html#comment-21407)) + +> [Crab Synth](https://lh3.googleusercontent.com/a-/AOh14GgDWPylqC3Tu2Tn2VKYsC4FGkgFlhb9leY7laYR) says: +> +> Fantastic Post… especially the comments… keep coming back to it, many times over the years… and i must commend you Shai… you had an appropriate answer for everything…. and even though conventions, preferrences and styles will continue to segragate users, causing them to pick a side… i believe by reading the comments and your replies i have a much better understanding of how to separate the hype from the features of React and how Java can achieve everything asked of it. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-is-superior-to-react-native-in-practically-every-way.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/java-mobile-dev-webinar-recap.md b/docs/website/content/blog/java-mobile-dev-webinar-recap.md new file mode 100644 index 0000000000..63ab239bf5 --- /dev/null +++ b/docs/website/content/blog/java-mobile-dev-webinar-recap.md @@ -0,0 +1,167 @@ +--- +title: Java Mobile Development Webinar Recap +slug: java-mobile-dev-webinar-recap +url: /blog/java-mobile-dev-webinar-recap/ +original_url: https://www.codenameone.com/blog/java-mobile-dev-webinar-recap.html +aliases: +- /blog/java-mobile-dev-webinar-recap.html +date: '2015-08-11' +author: Steve Hannah +--- + +![Header Image](/blog/java-mobile-dev-webinar-recap/webinar-header-graphic.png) + +Tuesday morning I held a webinar on Java mobile development using Codename One. First of all, I’d like to thank all who signed up and attended. Unfortunately there were some technical difficulties with the Webinar software that caused some major glitches. Double thanks to those who endured and stayed to the end. We’ve learned from this experience and we will do better in future webinars. + +Since most of the people who signed up for the webinar indicated that they had no experience with Codename One, I spent the first 10 minutes or so introducing the framework, and showing some demos of some existing apps to give participants an idea of the possibilities. + +The rest of the presentation was spent building custom social media app similar to facebook. I created a simple PHP/MySQL server-side application before hand and deployed it on the internet so that the mobile app would be able to connect to it from anywhere in the world. Therefore, the finished result, is actually a usable social network – though it is only “demo” grade, and I’ll probably take it down in a few months. + +Here are some screenshots of the app: + +![Screen shots](/blog/java-mobile-dev-webinar-recap/social-app-screenshots.png) + +The tutorial was structured like a cooking show, where I break the development of the app down into 12 “steps”. By the end of it we have a working app. + +Since there were technical difficulties with the actual webinar, I “refilmed” it afterwards using Screenflow, and I am quite happy with the results. It has been posted on YouTube [here](https://youtu.be/8D-CEtWAgHk). + +And you can access the source of the app (both client and server) [here](https://github.com/shannah/social-network). + +Finally, you can try out the app on Android [here](http://cn-social-network-demo.weblite.ca/SocialNetwork-release.apk). + +## The Next Webinar + +In the next session, we will take this bare-bones, yet functional, social mobile app as a starting point and discuss ways to make it better. Since this is literally an app that was built in a day, there are obviously lots of low-hanging fruit that we can pick on. The agenda hasn’t been finalized, and the date isn’t set in stone, but it will be within the next two weeks, and some of the potential agenda items may include: + + 1. Improving look and feel using styles, borders, and icons. + + 2. Adding Push support so users will be notified when news is posted, or when they receive friend requests. + + 3. Improving performance using various techniques including image compression, pre-sizing of images, network threads, and sprites. + + 4. Introducing Local storage for offline support. + + 5. Adding chat support + +If there are particular issues you would like to cover in the next webinar, please post them in the comments below, and I’ll see if I can incorporate them. + +### The Webinar Software + +For this webinar, I used GotoWebinar because I was familiar with GotoMeeting. Unfortunately there were some issues that make it less than a perfect fit for our needs. I’ve been reviewing Google Hangouts, and may try that out for the next one. If you have suggestions, I’m also interested in hearing what solutions you have used. + +Happy coding, and hope to see you all in the next session! +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **ugochukwu** — August 15, 2015 at 9:03 am ([permalink](https://www.codenameone.com/blog/java-mobile-dev-webinar-recap.html#comment-24191)) + +> thanks for this great tutorial +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-mobile-dev-webinar-recap.html) + + +### **ugochukwu** — August 15, 2015 at 9:04 am ([permalink](https://www.codenameone.com/blog/java-mobile-dev-webinar-recap.html#comment-22217)) + +> ugochukwu says: +> +> i would like you to put create group feature in the next webinar +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-mobile-dev-webinar-recap.html) + + +### **Lanre Makinde** — August 17, 2015 at 10:35 pm ([permalink](https://www.codenameone.com/blog/java-mobile-dev-webinar-recap.html#comment-22210)) + +> Lanre Makinde says: +> +> I really love this. Very straight to the nitty gritty details. And i really love the fact that the next webinar is going to be within 2 weeks. What a resourceful way to spend my summer break. However, there are a lot of stuffs i could ask you to treat in the next webinar. Below are a list you may take your pick. +> 1\. Hybrid chats i.e. chat handling messages, pictures, video and audio sharing +> 2\. Other social platform logins such as twitter, yahoo, etc +> 3\. Can we have the location manager as a background service with a view to showcase a users/subscriber location accurately enough especially to showcase changes in geo coordinates. +> 4\. Status of chats/messsages/hybrid chats unread/unaccessed as well as a notification on of chat arrivals, etc +> Thanks +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-mobile-dev-webinar-recap.html) + + +### **kilani rabah** — February 2, 2016 at 1:13 pm ([permalink](https://www.codenameone.com/blog/java-mobile-dev-webinar-recap.html#comment-22600)) + +> kilani rabah says: +> +> how to solve his problem can ????: +> +> No GUI Entries available +> +> init: +> +> Deleting: C:UsersMoiDocumentsNetBeansProjectsCodenameOne6build[built-jar.properties]() +> +> deps-jar: +> +> Updating property file: C:UsersMoiDocumentsNetBeansProjectsCodenameOne6build[built-jar.properties]() +> +> Compile is forcing compliance to the supported API’s/features for maximum device compatibility. This allows smaller +> +> code size and wider device support +> +> compile: +> +> run: +> +> févr. 02, 2016 1:56:37 PM java.util.prefs.WindowsPreferences +> +> WARNING: Could not open/create prefs root node SoftwareJavaSoftPrefs at root 0x80000002. Windows RegCreateKeyEx(…) returned error code 5. +> +> java.lang.reflect.InvocationTargetException +> +> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) +> +> at sun.reflect.NativeMethodAccessorImpl.invoke([NativeMethodAccessorImpl.java]():62) +> +> at sun.reflect.DelegatingMethodAccessorImpl.invoke([DelegatingMethodAccessorImp…]():43) +> +> at java.lang.reflect.Method.invoke([Method.java]():498) +> +> at com.codename1.impl.javase.Executor$1$[1.run](:75) +> +> at com.codename1.ui.Display.processSerialCalls([Display.java]():1149) +> +> at com.codename1.ui.Display.mainEDTLoop([Display.java]():966) +> +> at [com.codename1.ui.RunnableWr…](:120) +> +> at [com.codename1.impl.Codename…](:176) +> +> Caused by: java.lang.NullPointerException +> +> at com.mycompany.myapp.SocialNetwork.init([SocialNetwork.java]():85) +> +> … 9 more +> +> Java Result: 1 +> +> BUILD SUCCESSFUL (total time: 19 seconds) +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-mobile-dev-webinar-recap.html) + + +### **Shai Almog** — February 3, 2016 at 3:34 am ([permalink](https://www.codenameone.com/blog/java-mobile-dev-webinar-recap.html#comment-22539)) + +> Shai Almog says: +> +> Did you create a GUI builder app or a handcoded app? +> +> The default is to create a handcoded app and if so you need to select the GUI builder option explicitly. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-mobile-dev-webinar-recap.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/java-mobile-dev-webinar-sequel-recap.md b/docs/website/content/blog/java-mobile-dev-webinar-sequel-recap.md new file mode 100644 index 0000000000..550c64d6db --- /dev/null +++ b/docs/website/content/blog/java-mobile-dev-webinar-sequel-recap.md @@ -0,0 +1,64 @@ +--- +title: 'Java Mobile Development Webinar 2: The Sequel' +slug: java-mobile-dev-webinar-sequel-recap +url: /blog/java-mobile-dev-webinar-sequel-recap/ +original_url: https://www.codenameone.com/blog/java-mobile-dev-webinar-sequel-recap.html +aliases: +- /blog/java-mobile-dev-webinar-sequel-recap.html +date: '2015-08-30' +author: Steve Hannah +--- + +![Header Image](/blog/java-mobile-dev-webinar-sequel-recap/webinar-header-graphic.png) + +On Thursday morning we rolled the cameras for chapter 2 of our exciting new webinar series. This time around there were far fewer (though not zero) technical issues, and we were able to share a productive hour of mobile app development in the company of our fellow coders. + +[Last time](https://www.codenameone.com/blog/java-mobile-dev-webinar-recap.html), we built a [social media app](https://github.com/shannah/social-network) similar to Facebook. It highlighted how you can easily build REST client using Codename One. This time around we changed directions and built a game: **Classic Flickr Concentration**. Basically it is a matching game where you get a set of cards, and you tap them to flip them over. You just need to find the matches. My two-year-old daughter loves this game, by the way. + +Here is a 1-minute screen-cast of the game being played side-by-side on both an iPad Air 2, and a Nexus 5: + +After the tutorial, Clement Levallois spoke a little bit about CodApps and its upcoming bus tour around Europe to teach beginners how to build mobile apps. + +### Video of the Webinar + +A video recording of the webinar: + +Alternatively, the tutorial portion can be viewed [here](https://meet32335047.adobeconnect.com/p1p028qhco7/) using Adobe Connect’s webinar viewer. This version allows you to experience the webinar almost like it was live. You can see the chats, and there are helpful book marks to navigate directly to parts of the tutorial that interest you. + +### Source Code + +Get the full source code for the demo project from the [github repo](https://github.com/shannah/cn1-flickr-concentration-demo). + +You can also download the [android apk](https://github.com/shannah/cn1-flickr-concentration-demo/releases/download/1.0/e14a5a8a-74fc-4833-9a8d-653d1e86c59e-1440639554842-ClassicFlickrConcentration-release.apk) directly to try it on your device. + +### We Want Your Input + +Now that we have completed two webinars, we would are working on scheduling content further in advance. We will be holding them every two weeks and we’d like your input. + + 1. What kinds of topics would you like to have covered? + + 2. Would you like to share any of the work you’ve been doing? Do you have a cool app or sample that you have built in Codename One that you’d like to share? Let us know. + +I think we all had a good time talking and learning about Codename One. Hope to see you all there for the threequel. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Steve Nganga** — August 31, 2015 at 4:13 pm ([permalink](https://www.codenameone.com/blog/java-mobile-dev-webinar-sequel-recap.html#comment-22141)) + +> Steve Nganga says: +> +> Hi Steve….Great job there…We would like to see a tutorial where you are using native interfaces +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-mobile-dev-webinar-sequel-recap.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/java-one-detailed-trip-report.md b/docs/website/content/blog/java-one-detailed-trip-report.md new file mode 100644 index 0000000000..61f04b683c --- /dev/null +++ b/docs/website/content/blog/java-one-detailed-trip-report.md @@ -0,0 +1,493 @@ +--- +title: Java One Detailed Trip Report +slug: java-one-detailed-trip-report +url: /blog/java-one-detailed-trip-report/ +original_url: https://www.codenameone.com/blog/java-one-detailed-trip-report.html +aliases: +- /blog/java-one-detailed-trip-report.html +date: '2013-09-28' +author: Shai Almog +--- + +![Header Image](/blog/java-one-detailed-trip-report/java-one-detailed-trip-report-1.png) + + + + +[ +![Uh... I'm standing on stage next to James Gosling during rehearsal. Achievement unlocked.](/blog/java-one-detailed-trip-report/java-one-detailed-trip-report-1.png) +](https://twitter.com/SeanMiPhillips) + + + +There is absolutely no way I can recall everything that went on in JavaOne but I will try to do my best. I arrived sick and on pretty strong medication for my sinuses so my recollection might be a bit hazy, I did meet great people and had loads of fun. + +Before JavaOne started I had a meeting with +[ +Arno +](http://www.puder.org/) +of the +[ +XMLVM +](http://xmlvm.org/) +project, I was hoping to get more facetime with him and to maybe actually code something together but he was on his way for the rest of the week due to other duties. We discussed some of the issues with XMLVM and the potential of forking vs. merging our changes with the main XMLVM code base. The way things look it seems that we will have to take over XMLVM or at least the iOS/Windows Phone ports. + + +Later in the conference I had a meeting with + +[ +Niklas Therning +](https://twitter.com/ntherning) +of +[ +RoboVM +](http://robovm.org/) +, who like Arno is a great and interesting fellow. + + +I’ve been giving a lot of thoughts to XMLVM and RoboVM over the past few months, both have done a lot of work and each has its advantages/disadvantages. I’ve asked +[ +Steve Hannah +](https://twitter.com/shannah78) +to run his benchmarks for me on devices with some settings I asked for. Initially it seemed that RoboVM smoked XMLVM but when running on the devices the differences became far less pronounced. + + + +Because of the way Codename One is built, we could potentially just flip a switch to our servers and builds will be performed with RoboVM instead of XMLVM (this would require a lot of work on our side but would be seamless to you). The main holdback for me is my conservative nature. XMLVM is a very safe choice: + + + 1. +We can debug it (although its inconvenient). + + 2. +We can maintain it, I’m sure we can maintain RoboVM too if Niklas decides to quit but we already know we can maintain XMLVM. + + 3. +If Apple changes something (e.g. new architecture like the 64 bit they just announced) we can support it instantly since we just use xcode. + +So currently we will stick with XMLVM but there are no final decisions here since we could potentially offer both backends as we move forward. + + + + + + +JavaOne started with a great +[ +NetBeans party +](https://blogs.oracle.com/geertjan/entry/youtube_netbeans_party_2013) +on Saturday night, I met a lot of great people at that party doing some interesting stuff (although its all hazy with the medication and the beer). I met +[ +Joonas Lehtinen +](https://twitter.com/joonaslehtinen) +at that party he is the founder and CEO of +[ +vaadin +](http://www.vaadin.com) +(who now have a great +[ +new NetBeans plugin +](https://blogs.oracle.com/geertjan/entry/official_netbeans_tools_for_vaadin) +), which is a name that I saw popup every now and again. I’m a heavy GWT user and love it but it has its limitations, I guess I didn’t pay enough attention (too busy with mobile) to notice that +[ +vaadin +](http://www.vaadin.com) +is really a hybrid solution that tries to merge the stuff I liked about Echo2 with the stuff I like about GWT. Very cool! One of the great things about their booth is that they literally had a pile of vaadin books as the giveaway, finally a show giveaway that is actually useful! + + + +Kudos on that one, we should definitely do something like that as well. It also gave me a chance to read something on takeoff and landing (3 connections on the way home) so I was able to finish that pretty hefty book (honestly I skimmed some parts such as installation). + +Another cool thing about vaadin is that they are an open source startup that has ±70 employees, really encouraging stuff on a personal level. + +On NetBeans day itself I was on my way to Moscone (if you are a long time alumni this alone should provide you the reason to attend NB day, its at Moscone), when I ran into +[ +Geertjan +](https://blogs.oracle.com/geertjan/) +. We both walked to the first session of the day entered the room and there sitting and working bright and early is Dr. James Gosling. Alone. + +People reading this blog can probably imagine my feeling at that moment, but I’m an entrepreneur first and human being second… I instantly descended on him like locust pitching Codename One and giving him the birds eye view pitch. + +He was great and expressed interest, at the end of the day I asked that he would join our advisory board and I have his email so I can continue begging thru that medium! So that alone was a huge thing for me on a personal and professional level. + +Gosling demoed his cool robots to the crowd, being a mobile/embedded guy (and having worked on robots as a kid) I really appreciate a lot of the stuff they are doing at +[ +liquid robotics +](http://liquidr.com/) +. They have amazing visualization tools for controlling these robots which I’m sure will really benefit from Codename One… I promised him that if he accepts my invitation I will personally port everything to Codename One and give him a great tablet UI to play with the robots. + +Gosling told the story of the NetBeans acquisition, having worked at Sun I can pretty much attest to the mindset behind it. The gist of the story is that Sun at some point decided they want a “big play” on development tools and didn’t have anything good (because they kept killing internal projects so as not to compete with Borland et. al.). So they were looking for a billion dollar acquisition and came across Forte which was making mainframe tools (totally unrelated), Gosling tried to convince management to buy NetBeans but they decided that the price was too low so its not a “big play”. Eventually the compromise was to buy both (he put it as: the price for NetBeans was a rounding error on the Forte deal). + +Years later Forte is effectively nothing and NetBeans has 1.4m active users. + +There were a lot of other great talks that day but frankly I was all jagged up on Gosling and I don’t remember anything. I vaguely remember my talk on that day too although from feedback I got it was apparently given. I think I also had a sugar rush from all the great cupcakes +[ +Tinu +](https://twitter.com/netbeans) +ordered for the event celebrating 15 years of NetBeans (Google is also 15 years old this week, coincidence???). + + +Nathan Howard wrote a +[ +great blog post highlighting the NetBeans plugins +](http://blog.idrsolutions.com/2013/09/6-must-have-ide-plugins-featured-at-javaone/) +that were presented that day. + +In the middle of the NetBeans day we left for the keynote (in Moscone again which was cool), there were quite a few technical glitches in the keynote which is pretty shocking. I remember working on keynote presentations when at Sun, the level of work and rehearsal is astounding and having tech issues in that setting is really surprising. + +The keynote talked about what a great year this was for Java, I understand the need to get people enthusiastic and excited in a keynote (and be positive) but ignoring the security issues and NSA warnings etc. (within the keynote) is a bit much. + +The thing is Oracle actually has a security track in JavaOne now and is doing a lot of things to fix the problems we saw this year, I’d much rather hear “we had a tough year on this front but here is how we are fixing it”. The keynote was mostly anemic talking a lot about the embedded effort which is very interesting (the internet of “things”), but there was very little content there that was interesting to me personally as a mobile developer that isn’t a mobile HTML developer or an embedded developer. + +The day ended with a BoF about contribution to the JDK narrated by Daniel Sachse and Helio Frota, I came because of the description of the BoF which was pretty in line with Daniel’s presentation. However, it seems the committee that approved the BoF unified two separate and unrelated talks into one causing some frustration in the audience most of whom came for the description which was taken from Daniels talk. + + + + +The next day started with a session of notify your mobile clients by +[ +Jay Balunas +](https://twitter.com/tech4j) +and +[ +Matthias Wessendorf +](https://twitter.com/mwessendorf) +of the JBoss team at RedHat, they talked about sending push messages from the server. The talk was good, geeky and coherent. I think they made the problem seem a bit easier than it really is in the real world, they have an open source project called +[ +AeroGear +](http://www.aerogear.org/) +which I will be sure to check out the next time I look at our push code. + +Next on +[ +Richard +](https://twitter.com/richardbair) +and +[ +Jasper +](https://twitter.com/jasperpotts) +gave their annual what’s new in JavaFX talk which was pretty interesting. To me the biggest announcement by far: one thread! + +Up until now if you wanted to touch JavaFX from Swing you had to mix the threads since both have their own EDT. This is pretty similar to Codename One only imagine having 2 EDT’s and keeping track of both while you have your own code running. That isn’t horrible for simple use cases but in the case of our webkit and graphics implementation this is something that is REALLY hard to get right. They added an experimental flag that effectively unifies both threads into one thread, this should make migrating code way easier. They announced a lot of other stuff from 3d to embedding Swing in FX (up until now you could only embed in the opposite direction). + +I grabbed Richard for a chat, we have known each other online for quite a while mostly thru the work I did for SwingX’s open source project and in my properties work later on (and now thru Codename One). We ended up going to lunch with Richard, Jasper and +_ +Steve +_ +Northover. Apparently they now work very closely with Daniel Blaukopf who is a great friend from the Sun Microsystems WTK team days and one of the smartest people I know. We had some lunch and chatted a bit about FX and Codename One. It was a very interesting conversation but there is no point of going into details at this point in time. + +I missed a session and arrived at a session on Clojure, I didn’t like Clojure when it was called Lisp and that feeling remains the same. Trying to push a language like Clojure is like trying to get us all to use superior keyboard layout (e.g. Dvorak), probably won’t happen. These things are rooted too deep, but maybe I’m old (strike that, I am old who knows?). + +I ran into a friend so I was late to the multi-device session by +[ +David Campelo +](https://twitter.com/davidcampelo) +. I think I met David years ago when working for Sun, Chen and him know each other from our work on GingaJ which effectively put LWUIT on TV screens in Brazil. He gave an interesting demo about connecting tablets to the currently playing content on a TV, that is indeed an interesting direction to explore. I understand that the level of engagement in such experiences is tremendous and this is probably the future for such tools. + +Unfortunately his demo didn’t work, I can feel his pain. Its really hard to show network/device stuff especially with proprietary chains involved. There are so many points of failure which is why I always bring a ready made video of the demo in case of such a failure. This works like Murphy’s law, when you take that precaution the demo never fails… + +I then went on the +[ +Matthew +](https://twitter.com/matthewmccull) +‘s GIT on NetBeans Hands On Lab. I am not a fan of Hand On Labs and rarely take them (I never liked sitting in classrooms), I went simply because I was so impressed by Matthew following his JavaZone talk and wanted to see more. Matthew is indeed as great a teacher as he is a speaker, he was very interactive and I feel I understand GIT better now. If you happen to see his name at a conference you are attending I highly recommend you check it out, I think its always a good policy to just go to sessions with good speakers. Even if the subject isn’t interesting to you right now you can learn so much. + +In the past we had a lot of issues with GIT especially for Chen who is using Windows where the GIT GUI support isn’t as good as the SVN integration. I’m assuming some of this got fixed and it also seems we used GIT somewhat like Teamware (the gradfather of GIT) which I always loved and Chen really hates with a vengeance. Maybe its time to switch back to github, I love their UI and a lot of the things about it. I wonder how easy it would be to migrate a Google code project (probably should have asked Matthew). + + + +I then rushed to the JCP party on the roof of the Hilton, it had nice food and some interesting people but I couldn’t stay and ran off to a BoF on Swing & JavaFX. On my way to the BoF room I ran into +[ +Tinuola Awopetu +](https://oracleus.activeevents.com/2013/connect/speakerDetail.ww?PERSON_ID=5B887663459DE248B1E37D23F1023BA5&tclass=popup) +who does the marketing for the NetBeans team, we started chatting and it turns out she had her own panel BoF starting just then titled: “So You Want to Be a Published Technical Author?”. + + +A friend from Sun and one of the best technical writers I know +[ +Jonathan K +](http://www.jonathanknudsen.com/) + +[ +nudsen +](http://www.jonathanknudsen.com/) +(who also wrote one of the first LWUIT tutorials) used to describe book authoring as torture. So I don’t want to write a book. + + +However, I had fun talking with Tinu and + +thought I might as well check out the BoF. I’m glad that I did. + + +It featured 5 panelists: + + +[ +Erol Staveley +](https://twitter.com/ErolStaveley) +– publisher at Packt + +[ +Joel Murach +](http://www.amazon.com/Joel-Murach/e/B001JP7JQI) +– who is both an author and publisher at Mike Murach & Associates + +[ + + +Meghan Blanchette +](https://twitter.com/MeghanORM) +– editor at O’Reilly Media + + +[ +Arun Gupta +](https://twitter.com/arungupta) +– needs no introductions but in this case he came as an +[ +author +](http://www.amazon.com/Arun-Gupta/e/B00DWBZ3NI/ref=sr_ntt_srch_lnk_1?qid=1380465054&sr=1-1) +. + + +[ + + +David Heffelfinger +](https://twitter.com/ensode) +– an established author of +[ +several books +](http://www.ensode.com/books.jsf) +. + + + + + +This was a very interesting/fun panel, I hadn’t thought about the option of writing a Codename One book before this panel but I am now entertaining the thought. + +Just goes to show that you should always be open at Java One. + + + +The next day started by touring the exhibition floor, I was on a tight schedule running around to very specific booths of interest. Last year I was so busy I didn’t get to see the pavilion even once, so I was very careful and methodological this year. There were many interesting booths from IBM, RedHat, ARM etc. but the startups were more bold. CloudBees literally dressed all their personnel as bees, including head of marketing and (male) CEO. Amusing, but I think I’m too dry to do something like that. + +“Practical Pros and Cons of Replacing Swing with JavaFX in Existing Applications” was the title of a surprisingly interesting session. I added it to my list because it was lead by +[ +Geertjan +](http://twitter.com/GeertjanW) +but pretty much everyone on the panel had an interesting story. It focused on developers using the NetBeans platform (platform not just the IDE) for their development who incorporated JavaFX in various ways to reap the benefits of improved UI visualizations. + +[ +Sean Phillips +](https://twitter.com/SeanMiPhillips) +presented the app he has been working on for NASA (later on he showed it in the +[ +community keynote +](https://blogs.oracle.com/javaone/entry/the_javaone_2013_java_community) +, I think he got a dukes choice award for it), it is a NetBeans platform/FX based visualization of spacecraft motion in formation. This includes amazing visualizations for NASA scientists, I suggest checking out a small portion of his demo in the community keynote, very compelling. What doesn’t really show in the keynote is how excitable, enthusiastic and passionate he is about this technology. + +[ +Timon Veenstra +](https://twitter.com/TimonVeenstra) +presented a pretty cool NetBeans platform app that enables +[ +crop management for farmers +](http://agrosense.eu) +interesting stuff. They won a Duke’s choice award. Its pretty cool. + +[ +Rob Terpilowski +](https://twitter.com/RobTerp) +presented the work that he has been doing at +[ +Lynden +](http://www.lynden.com/) +which is a major shipping company. They are using FX to make the UI’s of their rather elaborate tables more visually appealing and usable. + +I then went to watch “Play Framework Versus Grails Smackdown” which was delivered by two brilliant speakers: +[ +James Ward +](https://twitter.com/_JamesWard) +& +[ +Matt Raible +](https://twitter.com/mraible) +. The talk was great however they gave a member of the audience in the front seat a really loud bell (or gong) and whenever one of them “delivered a smackdown” he rang the bell really loudly. I was in the back and had a headache 20 minutes into the talk. Left to the speaker room next door where the bell was also heard only softly. + + + +There are two reasons I went to the BoF “Teaching Java with Minecraft, Greenfoot, and Scratch”, +[ +Daniel Green +](https://twitter.com/dangjavageek) +& +[ +Arun Gupta +](https://twitter.com/arungupta) +. My daughter is still a bit too young for programming I’ll probably have to start next year when she is 4. The session was fun and engaging, but the real kicker came later… All thru the session Arun dropped references to teaching his son to work on the Minecraft source code. In the general session his son (Aditya) got on stage and stole the entire JavaOne show, he launched Eclipse and went into a compelling demo (and anyone who ever demoed source code modification on stage knows this is HARD and BORING). The kid had the audience eating out of the palm of his keyboard, it was one of the best demos I saw on the JavaOne stage and the audience was totally with him as he complained about Eclipse or lamented on a method needing to be overriden “not sure why”. James Gosling followed him noting that now he wants to become a minecraft hacker! + + + + +Wednesday started with a session by +[ +Nuvos +](http://nuvos.com/) +who are launching a WORA mobile solution in Java using a build cloud (sounds familiar?). They had a booth at the pavilion so I got a chance to talk to them and figure them out a bit. +[ +Kevin +](https://twitter.com/nuvosKevin) +is the founder/CEO of the company, they effectively started as a consulting project that grew into a solution for mobile. + + +Kevin is a great guy, we spent quite a while talking before and after his session. It might surprise some readers but we do wish them the best of luck, a rising tide raises all boats and our shared success would mean the success of Java & WORA for mobile as a whole. + + +* * * + + + + +[ +![Picture](/blog/java-one-detailed-trip-report/java-one-detailed-trip-report-2.jpeg) +](/img/blog/old_posts/java-one-detailed-trip-report-large-3.jpeg) + +Jaroslav Tulach + + +A bit later I attended a great session “The Chuck Norris Experiment: Running Java in Any Browser Without a Plug-in” which was given by +[ +Jaroslav Tulach +](https://twitter.com/JaroslavTulach) +(co-founder of NetBeans or Xelfi for us old timers) and +[ +Anton Epple +](https://twitter.com/monacotoni) +. The session presented the +[ +Bck2Brwsr +](http://wiki.apidesign.org/wiki/Bck2Brwsr) +JVM that JIT’s bytecode to JavaScript (yep), this isn’t GWT… The JIT literally takes a JAR opens it and jits the content to JavaScript which is then executed pretty efficiently on the V8-JIT (JIT nesting at its best). + +The ridiculous part is that it works and works well including debugging and decent IDE environment pretty shocking stuff. Unfortunately it doesn’t support threading (and no WebWorkers aren’t threads). The session itself was great and surprisingly even the Chuck Norris jokes were funny, both Anton and Jaroslav have a great sense of humor coupled with the technical chops to make this session one of the better sessions I attended at Java One. + + +I tried to talk to them after the session but it was a bit too busy and I started talking with + +[ +Yusuke Yamamoto +](https://twitter.com/yusukey) +who I thought I didn’t know. Turns out he wrote an +[ +article about us +](http://www.atmarkit.co.jp/ait/articles/1210/30/news020_3.html) +last year and also apparently a +[ +presentation +](http://www.slideshare.net/yusukey/codename-one) +. He is also a former Twitter employee and the author of +[ +Twitter4J +](http://twitter4j.org/) +a very cool Twitter API allowing Java developers to work with the Twitter webservice easily. It would be great to port that to Codename One. + + +After the community general session I ran into + +Jaroslav & Anton hacking their way in the hall. I naturally descended on them and went into a long discussion with Jaroslav on thread support for Bck2Brwsr so we can add Codename One support for in browser apps. He is pretty adamant against this saying that it would impact performance considerably (he is right, this would require state transferal which is pretty tough), he pointed me at +[ +Doppio +](http://plasma-umass.github.io/doppio/about.html) +which is doing something similar but I can’t see a community working on this so I’m unsure of where they stand. + + + + + +Regardless you should check out + +the +[ +Bck2Brwsr +](http://wiki.apidesign.org/wiki/Bck2Brwsr) +JVM, its pretty amazing. + + +The last J1 session I attended was the +[ +RoboVM +](http://robovm.org/) +session, + +Niklas was great although he needs to seriously simplify his message to the audience some of whom didn’t really understand what LLVM meant. He had great attendance considering the fact that this session was announced just before J1 started so most people wouldn’t have seen it in their schedule builder tool (even moreso considering the fact that some people already left as the conference was winding down they literally started folding up the room around us). + + +I would describe RoboVM as a Xamarin for Java based on LLVM. Its an LLVM front end for Java that allows using the toolchain to build native iOS apps with native iOS API’s. Unlike Codename One which aims for WORA, RoboVM is targeted at avoiding Objective-C and giving a Java facelift to iOS development. Niklas did an amazing job in terms of tooling and the underlying technology and we are keeping a keen eye on this project, we spent a great deal of time talking about making a living from open source projects. I do hope that Niklas will find the model that works for him with RoboVM and is able to keep the amazing rate of progress he has shown so far. + + +JavaOne ended with the usual party at Moscone, however this year they merged it with the Open World party which was too big and sucked as a result. I miss the old garden party which was crowded yet intimate, where you actually knew some of the people in attendance. + + +Regardless, it was a fun JavaOne for me on a personal note. Hopefully next year will be as good or even better. + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — September 30, 2013 at 7:15 pm ([permalink](https://www.codenameone.com/blog/java-one-detailed-trip-report.html#comment-21640)) + +> Anonymous says: +> +> I’m wondering whether RoboVM has better stack trace support than XMLVM. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-one-detailed-trip-report.html) + + +### **Anonymous** — October 1, 2013 at 3:53 am ([permalink](https://www.codenameone.com/blog/java-one-detailed-trip-report.html#comment-22035)) + +> Anonymous says: +> +> Good question. +> +> Yes and no. You will still have issue on devices since symbols are stripped and since we won’t be using the native simulator you won’t see most of that anyway. +> +> I think that if we will start maintaining XMLVM we will make radical changes to it which will improve performance, size and stack trace support. I have some ideas on the matter which I discussed with Arno to verify their feasibility. Naturally this all boils down to time/effort. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-one-detailed-trip-report.html) + + +### **Anonymous** — October 4, 2013 at 2:07 pm ([permalink](https://www.codenameone.com/blog/java-one-detailed-trip-report.html#comment-21858)) + +> Anonymous says: +> +> I’m afraid I’m going to sound like a broken record, but thank you so much for this detailed report, it’s almost like being there! Do you know if/when the session videos will be available for viewing, like they did for 2012? Keynotes can only tell you so much… Also, I’m very intrigued by your JavaFX comment “It was a very interesting conversation but there is no point of going into details at this point in time.” We’ll stay tuned, I guess 😉 Congrats on the 21 millions devices! Love the ticker! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-one-detailed-trip-report.html) + + +### **Anonymous** — October 4, 2013 at 4:20 pm ([permalink](https://www.codenameone.com/blog/java-one-detailed-trip-report.html#comment-21910)) + +> Anonymous says: +> +> Thanks! +> +> As far as I know they should upload everything to [parleys.com]() but its not there yet. I wanted to reference some things I saw and checked there today. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjava-one-detailed-trip-report.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/javadoc-source-samples-that-dont-suck.md b/docs/website/content/blog/javadoc-source-samples-that-dont-suck.md new file mode 100644 index 0000000000..c517c723f0 --- /dev/null +++ b/docs/website/content/blog/javadoc-source-samples-that-dont-suck.md @@ -0,0 +1,88 @@ +--- +title: JavaDoc Source Samples That Don't Suck +slug: javadoc-source-samples-that-dont-suck +url: /blog/javadoc-source-samples-that-dont-suck/ +original_url: https://www.codenameone.com/blog/javadoc-source-samples-that-dont-suck.html +aliases: +- /blog/javadoc-source-samples-that-dont-suck.html +date: '2016-01-17' +author: Shai Almog +--- + +![Header Image](/blog/javadoc-source-samples-that-dont-suck/with-javascipt-gist.png) + +JavaDoc source code embeds suck! +I love JavaDoc but it didn’t age well. When you work with other tools (e.g. in the Microsoft world) suddenly the +embedded samples look amazing and “search” functionality is just built in! +**Why can’t we have that?** +JDK 9 is [introducing new support for search](http://mail.openjdk.java.net/pipermail/jdk9-dev/2016-January/003362.html) +but source embeds can be so much better and are a crucial learning tool… + +Since documentation and proper code samples are so crucial we decided to revisit our javadocs and start from +the ground up, to that point we created the new open source project: +[JavaDoc Source Embed](https://github.com/codenameone/JavaDocSourceEmbed). + +The goal of this project is to allow using github “gist” in JavaDoc which allows you to create JavaDoc that looks +like [this](https://www.codenameone.com/javadoc/com/codename1/location/LocationManager.html) +instead of the normally anemic source embeds. +If you are unfamiliar with [github gists](https://gist.github.com/) its essentially +a code snippet hosting service that both formats the code nicely and allows you to easily maintain it thru +github (fork, star, watch etc.). +The central hosting is the true “killer feature”, it allows you to embed the sample everywhere that’s applicable +instead of copying and pasting it. E.g. the [LocationManager](https://www.codenameone.com/javadoc/com/codename1/location/LocationManager.html) +is a good place to hold the sample but so is the [Geofence](http://codenameone.com/javadoc/com/codename1/location/Geofence.html) class. +In those cases we only had to copy this small snippet in the javadoc: + + + + +The only two problems with gist are its lack of searchability and the fact that it won’t appear in IDE’s that don’t +render JavaScript. The [JavaDoc Source Embed](https://github.com/codenameone/JavaDocSourceEmbed) +project effectively solves that by automatically generating a “noscript” tag with the latest version of the gist +so it appears properly everywhere it is referenced. + +We’ll try to update our javadocs but would be happy for pull requests and issues pointing at missing samples +and where they should be placed in the code. + +#### Developer Guide Wiki + +In other news we just finished the migration of the developer guide to the github wiki page and already it looks +radically different. The approach of using githubs wiki pages has its drawbacks and asciidoc does have +some pain points but overall I think this is a good direction for an open project. +[Ismael Baum](https://github.com/Isborg) made a lot of wiki edits fixing many +grammatical and logical errors picking up so many mistakes in the process! +Besides the many rewrites and fixes we made for the document we also authored a script that translates +Codename One class names to links into the JavaDoc. + +So now instead of just highlighting the mention of `LocationManager` you would see +[LocationManager](https://www.codenameone.com/javadoc/com/codename1/location/LocationManager.html) +which is far more useful. Notice that this shouldn’t affect things like code blocks only mentions of a +specific class. From this point on we’ll try to interconnect the documentation to produce a more coherent +experience with the docs. +I’d open source the script we used for the links but its mostly a bunch of very specific `sed` +commands which probably won’t be useful for anyone. We won’t run it again since its a “one off” script, +we’ll just need to keep the linking going. + +#### Feedback + +Do you know of other tools we can use to improve the state of our documentation? +We are looking for several things that still seem to be hard with the current toolchain: + + * Better JavaDoc integrations – ability to embed it into the existing web design would be wonderful! +CSS is a bit too limiting. + * Improving the look of the asciidoc PDF – Currently the PDF looks too academic in the opening page +there are some solutions for that but most seem hackish. + * Grammar & Style tools – There are some decent grammar checkers for word processors but +we couldn’t find anything that works with asciidoc. The same is missing for writing analysis tools that +can point out unclear writing. I saw that gitbooks has some interesting tools there but I’m unsure whether +we want to use it. + +Let us know if you are familiar with such tools or something else that we might not be aware of. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/javaone-2014-trip-report.md b/docs/website/content/blog/javaone-2014-trip-report.md new file mode 100644 index 0000000000..1c371289fe --- /dev/null +++ b/docs/website/content/blog/javaone-2014-trip-report.md @@ -0,0 +1,160 @@ +--- +title: JavaOne 2014 Trip Report +slug: javaone-2014-trip-report +url: /blog/javaone-2014-trip-report/ +original_url: https://www.codenameone.com/blog/javaone-2014-trip-report.html +aliases: +- /blog/javaone-2014-trip-report.html +date: '2014-10-06' +author: Shai Almog +--- + +![Header Image](/blog/javaone-2014-trip-report/javaone-2014-trip-report-1.jpg) + + + + +[ +![Shai & Chen](/blog/javaone-2014-trip-report/javaone-2014-trip-report-1.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-16.jpg) + + + + + + + + +This is going to be a radically different trip report, we weren’t just talking at Java One this year we were actually presenting with our own booth and would probably do so again next year. Last year we tried to purchase a booth as well but were unable to get in contact with the right person at Oracle before the conference sold out (which was a shame, I understand some pavilion space went for free). This year we were ready though and were able to secure a small space but it turned out to be a great conference to us and we got the word out far/wide. On the right you can check out Chen & Myself at our booth just as it was setup. + +I +[ +wrote already about our first session on NetBeans day with James Gosling +](http://www.codenameone.com/blog/cn1ml-javaone) +, the room was so packed that Steve Hannah couldn’t get in (standing room only). + +If you haven’t been to San Francisco its truly a unique microcosm within the USA, a beautiful city with painful poverty and noble ideas. Here are some unique pictures that represent that city perfectly in my mind. + + + + + + + +* * * + +[ +![](/blog/javaone-2014-trip-report/javaone-2014-trip-report-2.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-17.jpg "Spinning class outside in the middle of the day") + +[ +![](/blog/javaone-2014-trip-report/javaone-2014-trip-report-3.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-18.jpg "In the middle of the "bad side of town" there's a tweet") + +[ +![](/blog/javaone-2014-trip-report/javaone-2014-trip-report-4.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-19.jpg "A meter that counts the bicycles going by in the bicycle lane") + + + + + + +[ +![Empire of the sun concert](/blog/javaone-2014-trip-report/javaone-2014-trip-report-5.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-20.jpg) + + + + + + + +If you haven’t been to JavaOne in recent years (since it left Moscone) then you need to check out “Taylor st. Cafe”. Oracle literally closes a portion of Taylor street that passes next to the Hilton and sets up a coffee shop in the middle of the streets (the whole thing is carpeted and perimetered very efficiently). The effect is pretty amazing and on Sunday we had the first “official” JavaOne party over there which was pretty cool. I spoke with some interesting people and had a blast. + +On Monday thru Wednesday we spent all day in the booth talking to people and telling them about Codename One, by our estimates we pitched to about 700 different individuals in the 3 pavilion days so we didn’t get to see any sessions other than our own (a first for me at JavaOne). We did get to go to the parties at night if we could drag ourselves after running around pitching all day e.g. on the first night there was an empire of the sun concert. We didn’t know the band beforehand but they were pretty great and gave an amazing show filled with pyrotechnics which were damn impressive. + + + + + +* * * + +[ +![](/blog/javaone-2014-trip-report/javaone-2014-trip-report-6.gif) +](/img/blog/old_posts/javaone-2014-trip-report-large-21.gif) + +[ +![](/blog/javaone-2014-trip-report/javaone-2014-trip-report-7.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-22.jpg) + +[ +![](/blog/javaone-2014-trip-report/javaone-2014-trip-report-8.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-23.jpg) + +[ +![](/blog/javaone-2014-trip-report/javaone-2014-trip-report-9.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-24.jpg) + + + + + + +[ +![Picture](/blog/javaone-2014-trip-report/javaone-2014-trip-report-10.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-25.jpg) + + + + +Since the booth work was so busy we don’t have that much pictures other than this one taken by Geertjan (on the left you see Chen, Steve Hannah & me), we did give away all of the suitcase load full of shirts and brochures we brought to JavaOne and we also had a raffle to win a Moto 360 smartwatch Geertjan graciously did the name draw among the contestants and Chen handed the watch to the winner, in all the excitement we completely forgot to write down his name or details but we have his picture and the draw below. + + +* * * + +[ +![](/blog/javaone-2014-trip-report/javaone-2014-trip-report-11.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-26.jpg) + +[ +![](/blog/javaone-2014-trip-report/javaone-2014-trip-report-12.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-27.jpg) + +[ +![](/blog/javaone-2014-trip-report/javaone-2014-trip-report-13.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-28.jpg) + +[ +![](/blog/javaone-2014-trip-report/javaone-2014-trip-report-14.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-29.jpg) + + + + + + +[ +![Picture](/blog/javaone-2014-trip-report/javaone-2014-trip-report-15.jpg) +](/img/blog/old_posts/javaone-2014-trip-report-large-30.jpg) + + + + +Thursday was full with meetings, gift purchasing for the kids and our session. The session was literally in the last time slot at JavaOne and I saluted everyone in attendance for staying until the end. It was a tough session to do since my abstract was flawed and the session had multiple separate premises to it that weren’t clear, I think I handled it reasonably well and people laughed at my stupid jokes which is normally a good sign. + +I did the entire session from my iphone which was a mistake in retrospect since the display preview was too small and the display kept locking the screensaver (which never happened with the ipad), but I wanted to demo Codename One apps running on a real device which was pretty sweet. + +This post is actually going live from India where I just landed the other day, Namaste. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/javaone-booth-ios-8-issues-more.md b/docs/website/content/blog/javaone-booth-ios-8-issues-more.md new file mode 100644 index 0000000000..1e78f056a7 --- /dev/null +++ b/docs/website/content/blog/javaone-booth-ios-8-issues-more.md @@ -0,0 +1,118 @@ +--- +title: JavaOne Booth, iOS 8 Issues & More +slug: javaone-booth-ios-8-issues-more +url: /blog/javaone-booth-ios-8-issues-more/ +original_url: https://www.codenameone.com/blog/javaone-booth-ios-8-issues-more.html +aliases: +- /blog/javaone-booth-ios-8-issues-more.html +date: '2014-10-12' +author: Shai Almog +--- + +![Header Image](/blog/javaone-booth-ios-8-issues-more/javaone-booth-ios-8-issues-more-1.jpg) + + + + +[ +![Picture](/blog/javaone-booth-ios-8-issues-more/javaone-booth-ios-8-issues-more-1.jpg) +](/img/blog/old_posts/javaone-booth-ios-8-issues-more-large-2.jpg) + + + + + + + + + + + +I just published a +[ +LinkedIn article +](https://www.linkedin.com/pulse/article/20141013104245-87574-is-a-booth-at-javaone-worth-the-expense) +discussing the financials of a JavaOne booth, if you are a startup/vendor looking at conference booths I hope this provides some much needed transparency. I know that when we researched the issue the lack of information was very problematic. + +iOS 8 introduced a few regressions into Codename One which should now be mostly resolved. This is mostly due to Apple discarding support for some features that were previously deprecated but they didn’t offer any alternative for those features which is a bit of a problem. As a result of this the behavior of the picker component is somewhat different on iPhone’s running iOS 8. + +On an unrelated note we finished a process of migrating our Mac servers to Mavericks which is hugely important since it will allows us to migrate to xcode 6 for the new VM builds. + +We also moved all our AWS hosted servers to +[ +Digital Ocean +](https://www.digitalocean.com/?refcode=4f111db0d722) +(notice that is a reference link that will give you some credit to try it), generally we found them to be more affordable and FAR easier to manage than AWS which is ridiculously obtuse. + + + + + + + + + + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **Anonymous** — October 16, 2014 at 12:01 am ([permalink](https://www.codenameone.com/blog/javaone-booth-ios-8-issues-more.html#comment-22155)) + +> Anonymous says: +> +> Hey Shai, can’t seem to find your article on LinkedIn… Do you have a link? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavaone-booth-ios-8-issues-more.html) + + +### **Anonymous** — October 16, 2014 at 9:21 am ([permalink](https://www.codenameone.com/blog/javaone-booth-ios-8-issues-more.html#comment-21447)) + +> Anonymous says: +> +> Some changes in the CMS made links almost invisible. Not sure why… The words linkedin article are a link to this: [https://www.linkedin.com/pu…]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavaone-booth-ios-8-issues-more.html) + + +### **Anonymous** — October 16, 2014 at 2:10 pm ([permalink](https://www.codenameone.com/blog/javaone-booth-ios-8-issues-more.html#comment-22271)) + +> Anonymous says: +> +> Oh, ok. I was also trying to find it via the CodenameOne group on LinkedIn, but I can only see the posts Chen did (last one was “Showcase your app at JavaOne” a month ago. You should probably link it there as well for increased visibility! +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavaone-booth-ios-8-issues-more.html) + + +### **Anonymous** — October 17, 2014 at 3:06 pm ([permalink](https://www.codenameone.com/blog/javaone-booth-ios-8-issues-more.html#comment-22088)) + +> Anonymous says: +> +> Hi Shai, +> +> I will like to ask if Picker component is now working on iOS 8? Is there some code I have to add to my project? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavaone-booth-ios-8-issues-more.html) + + +### **Anonymous** — October 17, 2014 at 10:28 pm ([permalink](https://www.codenameone.com/blog/javaone-booth-ios-8-issues-more.html#comment-22015)) + +> Anonymous says: +> +> Just send a new build, no code changes required. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavaone-booth-ios-8-issues-more.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/javaone-trip.md b/docs/website/content/blog/javaone-trip.md new file mode 100644 index 0000000000..fa6310a3b6 --- /dev/null +++ b/docs/website/content/blog/javaone-trip.md @@ -0,0 +1,65 @@ +--- +title: JavaOne Trip +slug: javaone-trip +url: /blog/javaone-trip/ +original_url: https://www.codenameone.com/blog/javaone-trip.html +aliases: +- /blog/javaone-trip.html +date: '2013-09-22' +author: Shai Almog +--- + +![Header Image](/blog/javaone-trip/javaone-trip-1.jpg) + + + + + +![Picture](/blog/javaone-trip/javaone-trip-1.jpg) + + + + +I’m writing this from the lobby of the Hilton hosting the JavaOne conference a bit jetlagged, +[ +Geertjan +](https://blogs.oracle.com/geertjan/) +invited me to speak at the NetBeans day which was great. However, the best thing was meeting +[ +James Gosling +](http://nighthacks.com) +and talking to him about Codename One! + +I had a lot of doubts about making the trip so soon after +[ +JavaZone trip +](http://www.codenameone.com/3/post/2013/09/javazone-trip-report.html) +but +[ +Geertjan +](https://blogs.oracle.com/geertjan/) +convinced me by mentioning that there is a chance of meeting +[ +Gosling +](http://nighthacks.com) +which was pretty much the thing that convinced me. So for me the trip is now a huge success. + +I’ve also got a chance to meet +[ +Arno +](http://www.puder.org/) +again which is great, I was hoping for more face time with him so we could actually do some coding together but he had some unfortunate scheduling conflicts at the last moment. This is really important for me since we are currently in the position of re-evaluating and reimagining our iOS infrastructure especially in terms of graphics but also in VM capabilities. + +Met a lot of great people and companies around here so far, too many to mention. I’ll try to write a more detailed report as the conference winds down. + +* * * + +Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended…. If that is the case please let us know via the comments section below. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/javascript-beta-interactiondialog-popup.md b/docs/website/content/blog/javascript-beta-interactiondialog-popup.md new file mode 100644 index 0000000000..5b1f117d80 --- /dev/null +++ b/docs/website/content/blog/javascript-beta-interactiondialog-popup.md @@ -0,0 +1,39 @@ +--- +title: JavaScript Beta & InteractionDialog Popup +slug: javascript-beta-interactiondialog-popup +url: /blog/javascript-beta-interactiondialog-popup/ +original_url: https://www.codenameone.com/blog/javascript-beta-interactiondialog-popup.html +aliases: +- /blog/javascript-beta-interactiondialog-popup.html +date: '2015-06-07' +author: Shai Almog +--- + +![Header Image](/blog/javascript-beta-interactiondialog-popup/html5-banner.jpg) + +The JavaScript port is nearing beta stage which will start next week its already added support for most API’s +including SQL support and many other features. Once the JavaScript port is in beta it will become an enterprise +only feature so if you haven’t tried it yet you have one week to try your app. + +#### Interaction Dialog Popup + +One often requested feature of the `InteractionDialog` is support for popup dialog semantics +where the dialog can point at the originating component. You can now use the `showPopup` +method also on an `InteractionDialog` to provide pretty elaborate UI’s. + +One of the main use cases for such a dialog is to point at a component within the title area, e.g. with the `Toolbar` +API this can be very simple and intuitive. However, because we abstract components within the menu thru commands +its problematic to point the `showPopup` call at the right location, to solve this we added a new +method to both the `MenuBar` and `Toolbar` API’s: `findCommandButton(Command)` +Notice that this API isn’t guranteed to return anything, e.g. if you use the native menus which are the default +on Android you will get null as the result of that method. The same is probably true if you use overflow or other such API’s. +However, this API can also be useful for many edge cases such as manipulating the appearance of a command +dynamically which is currently pretty awkward. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/javascript-get-threaded.md b/docs/website/content/blog/javascript-get-threaded.md new file mode 100644 index 0000000000..d20c8f4216 --- /dev/null +++ b/docs/website/content/blog/javascript-get-threaded.md @@ -0,0 +1,225 @@ +--- +title: Javascript, Grow up and Get Threaded +slug: javascript-get-threaded +url: /blog/javascript-get-threaded/ +original_url: https://www.codenameone.com/blog/javascript-get-threaded.html +aliases: +- /blog/javascript-get-threaded.html +date: '2015-08-23' +author: Steve Hannah +--- + +![Header Image](/blog/javascript-get-threaded/html5-banner.jpg) + +The concept of threads in the Javascript community is a controversial one. The founders and leaders are dogmatically against threads, and have been from very early on. [This 2007 article by Brendan Eich](https://brendaneich.com/2007/02/threads-suck/) reveals his feeling on threads (they suck!) and the advancements in subsequent years seem to have followed this sentiment by vigorously avoiding anything thread-like. + +Countless “solutions” and workarounds have been developed by clever programmers to try to improve the situation without actually adding threads. Web Workers solve some concurrency issues, but don’t come close to solving the general case, and Promises are currently a popular way to make threadless code more readable. Now with ES6, we have generators and the yield statement offering yet a new ugly workaround for this glaring language omission. These are all ugly patches that make code less readable and less maintainable, not more. + +In the olden days, Javascript was only used for adding a little interactivity to web pages so keeping it “thead-less” made sense. It reduced complexity and precluded the possibility of running into complex race conditions or dead-locks related to threading. Guess what, Javascript, it’s not the olden days anymore. Serious developers are building serious apps in Javascript now, and they are bending over backwards to work around this deficiency. + +Netflix talks a little bit about how they deal with asynchronous programming in [this video](https://www.youtube.com/watch?v=a8W5VVGO-jA). The first part of the video shows “the problem” – which includes race conditions, callback hell, etc… If you’ve developed anything of decent size in Javascript, you are well aware of these problems. Their solutions appear to be optimal considering Javascript’s lack of threads. But it just pains me to see everybody quite happy to jump through these hoops when the answer is staring them in the face. Just support threads! + +[TeaVM](http://teavm.org) is a Java to Javascript compiler that supports threads by using static analysis to cleverly convert the application into continuations. I have been using it quite a bit over the past few months (we are using it as a platform to port Codename One into Javascript), and it has just reminded me how nice it is to program synchronously. + +For example any time you are writing a function that has to call a “slow” function, like making a network request, accessing local data (e.g. IndexedDB), you have to break it up into multiple callbacks in Javascript. Rather than having a single “black box” function that takes inputs and returns outputs, you have to consider whether that function will need to access any services that require a callback. + +Consider an example function that returns the current user’s age. Our first version might always have the user’s age stored in a variable so we don’t need to worry about callbacks + + + function getAge() { + return this.userAge; + } + +So you build other parts of the app to depend on this function. Then one day, your requirements change, and you **may** need to load the age from a data source. + +e.g. + + + function getAge() { + if (this.userAge === -1) { + self = this; + requestUserAgeFromService(function(response) { + self.userAge = response.age; + }); + } + return this.userAge; + } + +Well, the first time this is called, userAge won’t be initialized yet, so you need to jump through some hoops to make sure it’s loaded. For this reason, in Javascript, all APIs should really be written to use promises or callbacks JUST IN CASE you need to do something that you can’t do synchronously. + +Look at the same function in Java with TeaVM: + + + int getAge() { + if (userAge === -1) { + userAge = requestUserAgeFromService(); + } + return userAge; + } + +We don’t know what kind of stuff needs to happen under the hood of `requestUserAgeFromService()`, and we shouldn’t need to. It’s a black box. IMO this code is much more readable, and far easier to maintain than any solution involving promises, callbacks, generators – or ANY solution that can currently be used in Javascript. + +During the process of developing the Javascript port for Codename One, whenever I was adding a new feature, I would evaluate available Javascript APIs to see how best to achieve the feature. In many cases the APIs have required callbacks – because that’s how Javascript has to work. My first order of duty, then, is to write a synchronous wrapper API for the library so that I can use the code synchronously. This isn’t difficult using the built-in Java threading primitives like wait and notify. But the result is an API that is WAY easier to understand and maintain. And thus far more enjoyable to use. + +This period of being able to build web apps with threading has spoiled me. I don’t think I can go back to just plain Javascript. The lack is just too present. + +If you’re looking to build web apps that support threading, you can check out [TeaVM](http://www.teavm.org) and its related sub-project, [Flavour](https://github.com/konsoletyper/teavm-flavour), that provides bindings similar to Knockout and Angular. It’s not for every project, but once it reaches a certain size, being able to write code synchronously will pay dividends while providing a much more pleasant development experience. Codename One has supported threads from the beginning on every platform, and with the help of TeaVM we also support threads in the browser. + +I have been developing in both Java and Javascript for years, so needing to use Java to have threads is no big deal, but for Javascript developers it may be more of a “change” than they want. It is especially for **those** developers that Javascript needs to grow up and get threaded. +--- + +## Archived Comments + +_This post was automatically migrated from the legacy Codename One blog. The original comments are preserved below for historical context. New discussion happens in the Discussion section._ + + +### **BrendanEich** — August 24, 2015 at 4:20 pm ([permalink](https://www.codenameone.com/blog/javascript-get-threaded.html#comment-22161)) + +> BrendanEich says: +> +> This post is out of date in many ways, and it misses the reasons why threads suck for JS as a language used by millions of programmers (data races without any proof system like Rust’s ownership/type system to make races static errors; races leaking into pure JS objects; easily-misused primitives meant for compilers and experts, not appropriate in the most widely used programming language on the planet). Have you been tracking the SharedArrayBuffer and Atomics work by Lars T. Hansen at Mozilla? Or WebAssembly? +> +> Dogmatic equation of “threads” with “growing up” did not make the case. Compiling real C++ programs to asm.js did. SharedArrayBuffer and Atomics are not yet in standard JS, and even if they make it (which I think is likely; they’re on the agenda for the September TC39 meeting, but who knows?), they won’t be for almost all of the millions of hand-coding JS programmers. Because threads suck. +> +> /be +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavascript-get-threaded.html) + + +### **shannah78** — August 24, 2015 at 5:27 pm ([permalink](https://www.codenameone.com/blog/javascript-get-threaded.html#comment-22204)) + +> shannah78 says: +> +> Thanks for commenting. Big fan of your work. +> +> I have to concede that threads are involved in most “newbie” mistakes in java. If I had a nickel for every time I had to point out “You’re modifying the UI off the EDT — big no-no”, I’d be … more wealthy than I am. And you might be right about threads not being needed by most Javascript developers. But… +> +> “”” +> easily-misused primitives meant for compilers and experts, not appropriate in the most widely used programming language on the planet +> +> “”” +> +> This makes it sound like you have lower expectations of Javascript developers than other languages- as if JS is a training-wheel language that is only appropriate for newbies. I.e. don’t give them threads because they can’t handle threads. On the contrary, some of the best minds in the world are now working in Javascript for most of their productive hours. These guys can handle a few sharp objects. +> +> I do appreciate the caution in adding features that could confuse copy-paste coders, and things like SharedArrayBuffer/Atomics is definitely moving in the right direction. In fact due to this caution, Javascript is well positioned to add concurrency in a safe way. +> +> I’ve been doing some experimentation with [parse.com]() cloud functions – which requires me to use server-side JS – and I find myself wincing as I write the code and then realize — oh , have to make another db call here…. ok.. let’s wrap this in another promise, and change the flow of the entire function to work with promises now. Enjoyment factor just tanks as soon as I have to do that. +> +> I am watching the progress of WASM with anticipation, and I fully expect that JS will add threads – or at least the basis upon which threads could be implemented at some time in the future. I’d just like to see it sooner than later. I still contend that threads (or at least concurrency with easily shared memory) are a feature of any “grown-up” language, and JS devs need the option of removing the training wheels from time to time. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavascript-get-threaded.html) + + +### **Jason Mulligan** — August 25, 2015 at 10:31 am ([permalink](https://www.codenameone.com/blog/javascript-get-threaded.html#comment-22276)) + +> Jason Mulligan says: +> +> You don’t need threads in your “core” reactor, but do you need to understand how to write code for the env/language. Use promises for IO, events for user interaction and stateless functions for the rest; you’ll do fine. IPC may seem undesirable, but it forces you to really think about what you’re doing. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavascript-get-threaded.html) + + +### **shannah78** — August 25, 2015 at 2:15 pm ([permalink](https://www.codenameone.com/blog/javascript-get-threaded.html#comment-22084)) + +> shannah78 says: +> +> Of course you need to understand how to write code for the env/language. For JS you have three choices: +> 1\. All public APIs need to be written with return vals going to callbacks. +> 2\. All public APIs need to return promises. +> 3\. You may need to change the public API every time you make an implementation change due to the need to do some optional IO. +> +> Syntactically this results in the degradation of a nice language to a horrible kludge of functions chained together. StratifiedJS and TeaVM have good solutions for this – but it still seems laughable that everyone is happy with this status quo. +> +> Of course you don’t *need* threads. But that’s an argument in minimality. You don’t *need* objects, or functions, or arrays, or etc… either. They just make the language nicer to use. +> +> Promises and other reactive patterns for working asynchronously are all very clever developments by very smart people to solve a problem that shouldn’t need to be solved. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavascript-get-threaded.html) + + +### **Jason Mulligan** — August 25, 2015 at 2:47 pm ([permalink](https://www.codenameone.com/blog/javascript-get-threaded.html#comment-21478)) + +> Jason Mulligan says: +> +> 1\. CSP +> 2\. Futures +> 3\. PEBCAK +> +> I disagree with the rest, as I can only assume you’ve trapped yourself with a way of thinking. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavascript-get-threaded.html) + + +### **shannah78** — August 25, 2015 at 3:03 pm ([permalink](https://www.codenameone.com/blog/javascript-get-threaded.html#comment-22433)) + +> shannah78 says: +> +> Thanks for the CSP ref. Wasn’t familiar with that one. Looks promising. PEBCAK must have been a self reference. Cheer up. It will be ok. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavascript-get-threaded.html) + + +### **BrendanEich** — September 2, 2015 at 3:34 pm ([permalink](https://www.codenameone.com/blog/javascript-get-threaded.html#comment-22366)) + +> BrendanEich says: +> +> I have appropriate expectations for most programmers of as widely used and heretofore single-threaded a language as JS is. The vast majority of JS programmers should not touch SharedArrayBuffer or Atomics, period, full stop — even if a few are expert enough to do so. +> +> We can haggle about how tiny vs. minuscule the fraction representing those few is, but it’s very small. +> +> /be +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavascript-get-threaded.html) + + +### **Alexey Andreev** — September 4, 2015 at 4:14 am ([permalink](https://www.codenameone.com/blog/javascript-get-threaded.html#comment-24192)) + +> Alexey Andreev says: +> +> > easily-misused primitives meant for compilers and experts, not appropriate in the most widely used programming language on the planet +> +> There are still developers that can and want to deal with threads. 99% of developers use frameworks, and remaining 1% write them. The problem that the latter ones need more “powerful” features of a language, and they usually (I belive) realize what are they doing. Example is: when I write business code for an enterprise application in Java using Spring, Hibernate, Servlet container, I don’t bother with threads at all. On the other hand I don’t bother with “asyncronous” nature of underlying infrastructure, because there is not asynchronousity at all. Consider the following code: +> +> for (Role role : employee.getRoles()) { +> +> System.out.println(role.getName()); +> +> } +> +> Dependending on configuration, this code may cause additional SQL query. I mean getRoles method that may be marked as lazy association, so instead of returning simple ArrayList, it returns Hibernate implementation of List, which executes an SQL query as soon as data get fetches from the list the first time. So Hibernate end-user simply uses it without knowing how how Hibernate really works and when it makes SQL queries. +> +> I can’t do the same trick with callbacks or promises, since I first have to declare all of my associations, that might cause SQL queries during their resolution, as returning promises of lists (or sets) instead of simple list. +> +> Callbacks can be easily implemented with threads. Actor model can be easily implemented with threads. STM can be (not quite easily) implemented with threads. But according to my experience with implementing threads via callbacks in TeaVM, this is pain in the ass, requiring you to use advanced compiler hacker knowledge. +> +> > they won’t be for almost all of the millions of hand-coding JS programmers +> +> what about millions of Java programmers? +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavascript-get-threaded.html) + + +### **Asmithdev** — September 14, 2015 at 7:30 pm ([permalink](https://www.codenameone.com/blog/javascript-get-threaded.html#comment-22376)) + +> Asmithdev says: +> +> I guess you’ve never heard of [http://www.hamsters.io/]() +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavascript-get-threaded.html) + + +### **Asmithdev** — September 14, 2015 at 7:38 pm ([permalink](https://www.codenameone.com/blog/javascript-get-threaded.html#comment-22306)) + +> Asmithdev says: +> +> Threads don’t suck with the use of the current web worker API and transferrable objects…although I do agree the API itself sucks on many levels the memory model makes threading extremely safe, I’m not entirely sure why people are unwilling to open their minds up to multithreading in JavaScript as the problem isn’t the language but rather lack of creativity and dedication to making them usable in a practical way. I wrote WebHamsters ([http://hamsters.io]()) specifically for this very reason, the tools are freely available for use by anyone who cares to invest the time to learn them. I don’t know why you would throw the potential of 100’s of % performance improvements with automatic parallelization because something “sucks” on an idealogical level. +> +> [Log in to Reply](https://www.codenameone.com/wp-login.php?redirect_to=https%3A%2F%2Fwww.codenameone.com%2Fblog%2Fjavascript-get-threaded.html) + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/content/blog/javascript-media-restrictions.md b/docs/website/content/blog/javascript-media-restrictions.md new file mode 100644 index 0000000000..9e8cf7f6ae --- /dev/null +++ b/docs/website/content/blog/javascript-media-restrictions.md @@ -0,0 +1,63 @@ +--- +title: Javascript Media Restrictions to be Aware Of +slug: javascript-media-restrictions +url: /blog/javascript-media-restrictions/ +original_url: https://www.codenameone.com/blog/javascript-media-restrictions.html +aliases: +- /blog/javascript-media-restrictions.html +date: '2019-12-18' +author: Steve Hannah +--- + +![Header Image](/blog/javascript-media-restrictions/html5-banner.jpg) + +Codename One provides `play()` and `pause()` methods as part of the `Media` interface, which you can use to start and stop media clips programmatically. If you are deploying your app to the browser using the Javascript port, then you should be aware of some restrictions imposed by modern web browsers on media playback, and how to work around them. + +Modern browsers will only allow audio playback that is triggered by direct user interaction. This basically means that the user needs to press a button to trigger audio playback. + +If your app fits into this model (playing sounds only in response to user button presses), then you don’t have to worry about this restriction. But if you want to play sounds in other contexts, you might bump into this restriction. For example, you might want to play a sound in a **chat** app, in response to someone else’s message being posted (i.e. in response to a server event). Or you might want to play a sound in response to voice input, or location changes, or when a timer goes off. + +So what happens if you call `mySoundClip.play()`, and the browser disallows it on the grounds that it wasn’t in direct response to user interaction? Our media API catches this failure, and displays a popup-dialog saying “Media ready” with a “Play” button as shown here: + +![MediaPlayNow](/blog/javascript-media-restrictions/MediaPlayNow.png) + +When the user presses the “Play” button, then the media will start playing because this time it should “meet” the browser’s user-interaction requirements due to the user’s click on the ‘play’ button. + +### Make Sure to Call cleanup() + +The “media ready” popup dialog shouldn’t present a major problem for your app’s user experience. However, if you’re playing several audio clips, one after another, it could become annoying for the user to have to keep pressing “Play” for each clip. Luckily, the browser will “remember” if the user has authorized audio playback on a particular media element, so if you play your cards right, you may only need to prompt the user to play the first sound clip, and the subsequent ones will just be allowed by the browser. In the Javascript port, each `Media` object is mapped to its own `HTMLMediaElement` (an `