Skip to content
This repository has been archived by the owner on Sep 4, 2019. It is now read-only.

Submit Pull to Refresh sample. #81

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions PullToRefresh/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.swp
*.un~
*.bar
*.pyc
9 changes: 9 additions & 0 deletions PullToRefresh/.gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[submodule "blackberry-py"]
path = blackberry-py
url = [email protected]:HorizonXP/blackberry-py.git
[submodule "adn"]
path = adn
url = [email protected]:HorizonXP/python-adn.git
[submodule "requests"]
path = requests
url = [email protected]:HorizonXP/requests.git
6 changes: 6 additions & 0 deletions PullToRefresh/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
blackberry-py-pulltorefresh
===========================

A BlackBerry-Py sample that demonstrates pull-to-refresh with the App.net global stream.

Works on the release version of BlackBerry 10.0.9. Currently uses BBPy (http://blackberry-py.microcode.ca/) but the QML should work just fine in your C++-based project so you can implement pull-to-refresh functionality.
4 changes: 4 additions & 0 deletions PullToRefresh/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
'''Entry point for Tart Application on the Python side.'''

# blackberry_tart.py will import this module and execute App().start()
from .app import App
59 changes: 59 additions & 0 deletions PullToRefresh/app/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@

import tart

class App(tart.Application):
def onUiReady(self):
pass

def onGetGlobalStream(self):
from adn.adn import Adn
app = Adn()
self.stream = app.globalStream()
validStream = True
for item in self.stream['data']:
if 'html' in item:
item['html'] = item['html'].replace("<br>", "<br/>")
validStream = True
else:
validStream = False
if validStream:
tart.send('receivedGlobalStream', stream=self.stream)
import tempfile
temp_dir = tempfile.gettempdir()
import os
for the_file in os.listdir(temp_dir):
filepath = os.path.join(temp_dir, the_file)
try:
if os.path.isfile(filepath):
os.unlink(filepath)
except Exception as e:
print(e)
self.getAvatarImages()
else:
self.onGetGlobalStream()

def getAvatarImages(self):
from .multirequest import MultiRequest
multiRequester = MultiRequest(self.mapGetImage, 5)
requests = list()
for (index,item) in enumerate(self.stream['data']):
if 'user' in item and 'avatar_image' in item['user']:
requests.append(item['user']['avatar_image']['url'])
multiRequester.get(requests)

def mapGetImage(self, index, url):
import requests
import tempfile
r = requests.get(url)
f = tempfile.NamedTemporaryFile(delete=False)
try:
f.write(r.content)
filename = f.name
avatar_image = dict()
avatar_image['url'] = filename
avatar_image['index'] = index
tart.send('updateAvatarImage', avatar_image=avatar_image)
finally:
f.close()


32 changes: 32 additions & 0 deletions PullToRefresh/app/multirequest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

import threading
import queue


class MultiRequest:
DEFAULT_NUM_THREADS = 4

def __init__(self, handler, num_threads=DEFAULT_NUM_THREADS):
self.num_threads = num_threads
self.threads = []
self.queue = queue.Queue()
self.handler = handler


def get(self, requests):
if not self.threads:
for i in range(self.num_threads):
t = threading.Thread(target=self.run)
t.daemon = True
t.start()
self.threads.append(t)

for (index,r) in enumerate(requests):
self.queue.put((index,r))


def run(self):
'''called in a thread to process requests by calling the handler'''
while 1:
(index,url) = self.queue.get()
self.handler(index, url)
99 changes: 99 additions & 0 deletions PullToRefresh/assets/ADNPostItemComponent.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import bb.cascades 1.0
import "../tart.js" as Tart

ListItemComponent {
Container {
property int spacing: 25

topPadding: spacing
leftPadding: spacing
rightPadding: spacing

Container {
layout: StackLayout {
orientation: LayoutOrientation.LeftToRight
}
background: Color.create("#404040");
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Fill
minHeight: 150

property int border: 1

topPadding: border
bottomPadding: border
leftPadding: border
rightPadding: border

Container {
layout: StackLayout {
orientation: LayoutOrientation.LeftToRight
}
background: Color.create("#e2e2e2");
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Fill
minHeight: 150

property int padding: 5

topPadding: padding
bottomPadding: padding
leftPadding: padding
rightPadding: padding

Container {
layout: DockLayout {}
layoutProperties: StackLayoutProperties {
spaceQuota: 2.0
}

ImageView {
imageSource: ListItemData.user.avatar_image.url
preferredWidth: 200
preferredHeight: 200
scalingMethod: ScalingMethod.AspectFit
loadEffect: ImageViewLoadEffect.Subtle
}
}

Container {
layout: StackLayout {}
layoutProperties: StackLayoutProperties {
spaceQuota: 8.0
}

leftMargin: 25

Label {
text: ListItemData.user.username
horizontalAlignment: HorizontalAlignment.Left

textStyle {
fontWeight: FontWeight.Bold
}
}

Label {
text: "<html>" + ListItemData.html + "</html>"
multiline: true
horizontalAlignment: HorizontalAlignment.Left
}

Container {
layout: DockLayout {}
horizontalAlignment: HorizontalAlignment.Right

Label {
text: ListItemData.created_at
horizontalAlignment: HorizontalAlignment.Right
verticalAlignment: VerticalAlignment.Bottom
textStyle {
textAlign: TextAlign.Right
}
}
}
}
}
}
}
}
18 changes: 18 additions & 0 deletions PullToRefresh/assets/AppMenuDefinition.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import bb.cascades 1.0
import "../tart.js" as Tart

MenuDefinition {
signal triggerSettingsPage
signal triggerHelpPage

settingsAction: SettingsActionItem {
onTriggered: {
triggerSettingsPage();
}
}
helpAction: HelpActionItem {
onTriggered: {
triggerHelpPage();
}
}
}
15 changes: 15 additions & 0 deletions PullToRefresh/assets/HelpPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import bb.cascades 1.0
import "../tart.js" as Tart


Page {
Container {
layout: DockLayout {}

Label {
text: "Help Page"
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
}
}
}
64 changes: 64 additions & 0 deletions PullToRefresh/assets/MainPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import bb.cascades 1.0
import "../tart.js" as Tart

Page {
id: page
signal addItem(variant entry)
signal updateAvatarImage(int index, string url)

property bool showLoading: true

onAddItem: {
modelGlobalStream.append(entry);
showLoading = false;
}

onUpdateAvatarImage: {
var item = modelGlobalStream.value(index);
item.user.avatar_image.url = url;
modelGlobalStream.replace(index, item);
}

Container {
layout: DockLayout {}

background: bg.imagePaint
attachedObjects: [
ImagePaintDefinition {
id: bg
repeatPattern: RepeatPattern.XY
imageSource: "asset:///images/bg.amd"
}
]

ListView {
id: listGlobalStream
dataModel: ArrayDataModel {
id: modelGlobalStream
}
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Fill

leadingVisual: PullToRefresh {
onRefreshTriggered: {
console.log("Refresh triggered!", modelGlobalStream.size());
modelGlobalStream.clear();
showLoading = true;
Tart.send('getGlobalStream');
}
}

listItemComponents: [
ADNPostItemComponent {}
]
}

ActivityIndicator {
running: true
visible: page.showLoading
preferredWidth: 350
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
}
}
}
47 changes: 47 additions & 0 deletions PullToRefresh/assets/PullToRefresh.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import bb.cascades 1.0
import "../tart.js" as Tart

Container {
signal refreshTriggered

layout: StackLayout {}

ImageView {
id: imgRefreshIcon
imageSource: "asset:///images/refreshicon.png"
horizontalAlignment: HorizontalAlignment.Center
topMargin: 25
}

Label {
id: lblRefresh
text: "Pull down to refresh results..."
horizontalAlignment: HorizontalAlignment.Center
topMargin: 25
bottomMargin: 25
}

Divider {
opacity: 0.0
}

attachedObjects: [
LayoutUpdateHandler {
id: refreshHandler

onLayoutFrameChanged: {
imgRefreshIcon.rotationZ = layoutFrame.y;

if (layoutFrame.y >= 0.0 * layoutFrame.height) {
lblRefresh.text = "Release to refresh results..."

if (layoutFrame.y == 0) {
refreshTriggered();
}
} else {
lblRefresh.text = "Pull down to refresh results..."
}
}
}
]
}
15 changes: 15 additions & 0 deletions PullToRefresh/assets/SettingsPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import bb.cascades 1.0
import "../tart.js" as Tart


Page {
Container {
layout: DockLayout {}

Label {
text: "Settings Page"
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
}
}
}
3 changes: 3 additions & 0 deletions PullToRefresh/assets/images/bg.amd
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#RimCascadesAssetMetaData version=1.0
source: "bg.png"
repeatable: true
Binary file added PullToRefresh/assets/images/bg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PullToRefresh/assets/images/refreshicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading